We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 33238
    • 388 Posts
    Hello everyone.

    I'm uploading images into the content using CKEditor, the image format is normal <img src="image.jpg" />

    I want to implement Lazy load for the images in the content, so I need the image inside a data-src instead a src.

    It is easy with Jquery for example but the image is loaded before the Jquery make the change, even if it is loaded on the <head>.

    for the clients, I don't think is a good idea that they need to make that change manually, so I'm trying to find the way to do it before the DOM is read, might be OnWebPagePrerender for example.

    I'm using an AMAZING plugin to cut and resize the content images (AutoFixImageSize), I was thinking, might be possible modify it to save the new cropped image into a src-data instead just replace the original in the src?

    <?php
    /**
     * @name AutoFixImageSize
     * @version 1.0.2 pl
     * @author Gerrit van Aaken <[email protected]> April 2011 – January 2013
     *
     * @license GPLv2
     *
     * Fixes img elements with wrong width/height attributes. 
     * Uses phpThumbOf for generating correctly sized physical image files.
     *
     * Must be executed at "OnWebPagePrerender"
     */
    
    // get parsed document as string
    $str = $modx->resource->_output;
    
    // get configuration from global object
    $config = $modx->getConfig();
    
    // find all img elements with a src attribute
    preg_match_all('|\<img.*?src=[",\'](.*?)[",\'].*?[^>]+\>|i', $str, $filenames);
    
    // loop through all found img elements
    foreach($filenames[1] as $i => $filename) {
    
      $img_old = $filenames[0][$i];
      $allowcaching = false; // pessimistic
    
      // is file already cached?
      if (strpos($filename,"?") == false || strpos($filename,"/phpthumb") == false) {
    
        // check if external caching is allowed
        if (substr($filename,0,7) == "http://" || substr($filename,0,8) == "https://") {
          $pre = "";
          if ($config['phpthumb_nohotlink_enabled']) {
            foreach (explode(",", $config['phpthumb_nohotlink_valid_domains']) as $alldomain) {
              if ( strpos(strtolower($filename), strtolower(trim($alldomain))) != false) {
                $allowcaching = true;
              }
            } 
          } else {
            $allowcaching = true;
          }
        } else {
          $pre = $config['base_path'];
          $allowcaching = true;
        }
      }
      
      // do we have physical access to the file?
    
    $mypath = $pre.str_replace('%20', ' ', $filename);
      if ($allowcaching && $dimensions = @getimagesize($mypath, $info)) {
    
        // find width and height attribut and save value
        preg_match_all('|width=[",\']([0-9]+?)[",\']|i', $filenames[0][$i], $widths);
        if (isset($widths[1][0])) {
          $width = $widths[1][0];
        } else {
          preg_match_all('|width:\s*([0-9]+?)px|i', $filenames[0][$i], $widths);
            if (isset($widths[1][0])) {
              $width = $widths[1][0];
            } else {
              $width = false;
            }
        }
        preg_match_all('|height=[",\']([0-9]+?)[",\']|i', $filenames[0][$i], $heights);
        if (isset($heights[1][0])) {
          $height = $heights[1][0];
        } else {
          preg_match_all('|height:\s*([0-9]+?)px|i', $filenames[0][$i], $heights);
            if (isset($heights[1][0])) {
              $height = $heights[1][0];
            } else {
              $height = false;
            }
        }
    
        // if resizing needed...
        if (($width && $width != $dimensions[0]) || ($height && $height != $dimensions[1])) {
    
          // prepare resizing metadata
          $filetype = strtolower(substr($filename, strrpos($filename,".")+1));
          $image = array();
          $image['input'] = $filename;
          $image['options'] = "f=".$filetype."&h=".$height."&w=".$width."&iar=1"; 
    
          // perform physical resizing and caching via phpthumbof
          $cacheurl = $modx->runSnippet('phpthumbof',$image);
    
          // set freshly cached image file location into old src attribute
          $img_new = str_replace($filename, $cacheurl, $img_old);  
    
          // replace old image element with new one on whole page content
          $str = str_replace($img_old, $img_new, $str);  
        }
      }
    }
    
    // exchange the output string with the replaced one
    $modx->resource->_output = $str;
    


    it is that possible, any other ideas?

    thank you very much.

    Cheers

    This question has been answered by donshakespeare. See the first response.

      --
      ysanmiguel.com
      • 42562
      • 1,145 Posts
      Very interesting ...
        TinymceWrapper: Complete back/frontend content solution.
        Harden your MODX site by passwording your three main folders: core, manager, connectors and renaming your assets (thank me later!)
        5 ways to sniff / hack your own sites; even with renamed/hidden folders, burst them all up, to see how secure you are not.
        • 33238
        • 388 Posts
        Any ideas to just change the src to data-src?
        that might be enough because that will block the image load, once is blocked will be easy with jquery add a src="loaging.gif" and the viewport/lazyLoad behaviour, but the DOM is going to be already loaded without images...

        HEEELP haha thank you!!!
          --
          ysanmiguel.com
          • 42562
          • 1,145 Posts
          YES it is very much possible in PHP and JS

          Create an output modifier snippet, no need for plugin.
          [[*content:lazyImages]]

          I'll post the PHP code later .... but here is the general PHP idea:
          Use DOMDocument() class to search for each image (getElementsByTagName) in the input string (in this case MODX content)
          Then loop through the items in the array ...
          setAttribute data-src and
          removeAttribute src

          In this way the browser will never even see the image src attribute ...

          But until then, here are functional alternatives

          //fast raw JS solution
          //load in the head before all else - even jQuery
          var region = document.getElementById("content");
          if (region) {
            var img = region.getElementsByTagName("img");
            for (i = 0; i < img.length; i++) {
              var src = img[i].src;
              img[i].removeAttribute("src");
              img[i].setAttribute("data-src", src);
            }
          }

          //jQuery solution
          //deal with the HTML images as soon as DOM is ready
          $(document).ready(function() { 
            $("#content img").each(function(){
              var src = $(this).attr("src");
              $(this).attr("data-src", src).removeAttr("src");
            });
          });


          I hope that helps. Cheers
            TinymceWrapper: Complete back/frontend content solution.
            Harden your MODX site by passwording your three main folders: core, manager, connectors and renaming your assets (thank me later!)
            5 ways to sniff / hack your own sites; even with renamed/hidden folders, burst them all up, to see how secure you are not.
            • 33238
            • 388 Posts
            Mate thank you very much for the answer, but I'm so bad with php, can you help me with the code please?

            the js is ok, it's not a problem.

            thank you mate!
              --
              ysanmiguel.com
              • 2762
              • 1,198 Posts
              for Evo, but should be easy convert to Revo

              case "OnWebPagePrerender" :
              
              $modx->documentOutput= str_replace(' src="assets/images/',' src="'.$LoadingImage.'" class="'.$ResponsiveClass.'" data-src="assets/images/',$modx->documentOutput);
              


              and you can pass a loading image placeholder, and a responsive class (ie:bootstrap img-responsive)

              Using Unveil.js (lightweight and nice Lazy Load) https://github.com/luis-almeida/unveil

              http://www.tattoocms.it/extras/plugins/unveil-images-plugin.html

              you can see the plugin at work on all the site's pages
                Free MODx Graphic resources and Templates www.tattoocms.it
                -----------------------------------------------------

                MODx IT  www.modx.it
                -----------------------------------------------------

                bubuna.com - Web & Multimedia Design
                • 42562
                • 1,145 Posts
                You assume you know the src of the image
                src="assets/images/'
                  TinymceWrapper: Complete back/frontend content solution.
                  Harden your MODX site by passwording your three main folders: core, manager, connectors and renaming your assets (thank me later!)
                  5 ways to sniff / hack your own sites; even with renamed/hidden folders, burst them all up, to see how secure you are not.
                  • 42562
                  • 1,145 Posts
                  SOLUTION ONE - MODX SNIPPET + PHP

                  Paste this in phpfiddle.org in CodeSpace Tab, hit Run - F9
                  and test this script: it works perfectly!
                  <?php
                  $content = '<br><br><img src="pita1.gif" /><br><br><img src="2pita.gif" /><br><br><img src="3pita.gif" />';
                  $dom = new DOMDocument();
                  $dom->loadHTML($content);
                  $imgs = $dom->getElementsByTagName('img');
                  foreach ( $imgs as $img) {
                   $src = $img->getAttribute('src');
                   $img->setAttribute('data-src', $src);
                   $img->setAttribute('title', $src); // just for test purposes
                   $img->removeAttribute('src');
                  }
                  echo $dom->saveHTML();  // in MODX, use: return $dom->saveHTML();
                  ?>


                  FOR MODX: create MODX Snippet, call it cuteLazyImages
                  $content = $input; //$input is the exact source to be attacked
                  $dom = new DOMDocument();
                  $dom->loadHTML($content);
                  $imgs = $dom->getElementsByTagName('img');
                  foreach ( $imgs as $img) {
                   $src = $img->getAttribute('src');
                   $img->setAttribute('data-src', $src);
                   $img->removeAttribute('src');
                  }
                  return $dom->saveHTML();


                  Usage, in template, placeholder, getResources listing etc etc

                  [[*content:cuteLazyImages]]

                  [[*myImagesTV:cuteLazyImages]]

                  [[+imagePlaceHolder:cuteLazyImages]]

                  *content, *myImagesTV, +imagePlaceHolder will serve as $input

                  No need for a dangerous plugin ...
                  In this way, only the area you want will be lazied, not your entire website or the entire internet ... wink




                  SOLUTION TWO - MODX PLUGIN + JS

                  Create Plugin - deadlyCuteImages
                  In the Plugin's System Events Tab: Ctrl +F and select [i]OnWebPagePrerender


                  And paste this in the plugin area itself
                  $myInvadingJS = '
                    var region = document.getElementById("content");
                    if (region) {
                      var img = region.getElementsByTagName("img");
                      for (i = 0; i < img.length; i++) {
                        var src = img[i].src;
                        img[i].removeAttribute("src");
                        img[i].setAttribute("data-src", src);
                      }
                    }
                  ';
                  $modx->regClientHTMLBlock($myInvadingJS);

                  https://rtfm.modx.com/revolution/2.x/developing-in-modx/other-development-resources/class-reference/modx/modx.regclienthtmlblock
                    TinymceWrapper: Complete back/frontend content solution.
                    Harden your MODX site by passwording your three main folders: core, manager, connectors and renaming your assets (thank me later!)
                    5 ways to sniff / hack your own sites; even with renamed/hidden folders, burst them all up, to see how secure you are not.
                    • 33238
                    • 388 Posts
                    Sorry mate I have been so busy but this is something very important to my project smiley

                    I tried the solution two but didn't work, nothing happened.

                    the first solution I just don't understand this line?
                    $content = '<br><br><img src="pita1.gif" /><br><br><img src="2pita.gif" /><br><br><img src="3pita.gif" />';


                    why is it? for testing reasons?

                    if I want to apply it for the images inside the div with class="contentArea" what should I do?

                    thank you very much donshakespeare
                      --
                      ysanmiguel.com
                      • 33238
                      • 388 Posts
                      Quote from: banzai at Sep 10, 2016, 10:51 AM
                      for Evo, but should be easy convert to Revo

                      case "OnWebPagePrerender" :
                      
                      $modx->documentOutput= str_replace(' src="assets/images/',' src="'.$LoadingImage.'" class="'.$ResponsiveClass.'" data-src="assets/images/',$modx->documentOutput);
                      


                      and you can pass a loading image placeholder, and a responsive class (ie:bootstrap img-responsive)

                      Using Unveil.js (lightweight and nice Lazy Load) https://github.com/luis-almeida/unveil

                      http://www.tattoocms.it/extras/plugins/unveil-images-plugin.html

                      you can see the plugin at work on all the site's pages

                      Nicola mate, no idea how to modify that for revo, I'm so stupid with PHP and ModX code parameters.

                      thank you!
                        --
                        ysanmiguel.com