Search…

X3 Photo Gallery Support Forums

Search…
 
User avatar
svenflock
Experienced
Topic Author
Posts: 34
Joined: 14 Oct 2019, 14:44

How to inject "folders" view within context and trigger comparison slider

31 Dec 2019, 16:24

Hi all,

happy new year :-)

I need a little help for tweaking:

For marketing reasons, my wedding landing page has to follow a very specific content structure. All the content of the site is coded in HTML within the content window or injected from external HTML files for easier editing.

I can handle all my page layout requirements more or less within the context content, though with one exception: folders view. I need to place a folders view inside „in the middle“ of a context, i.e. I need to inject the auto generated folders code within the context. X3 only allows me to specify the order of folders, gallery and context.

Please see my site at https://ziin-hochzeitsfotograf-duesseldorf.de/

The current setup is configured to show the folders first followed by the context (gallery view is disabled). But I need the folders view to move freely within the context. Is there a widget for that?


Alternatively, if I cannot change that: is there a way to inject the remaining context after the folders have been rendered? Is there a place to insert HTML code before the footer is injected?


My second question is: what JavaScript function do I have to call to initialize the comparison slider? The help states that the code is analyzed and JS/CSS classes are loaded after detection. As described above, a lot of code is dynamically injected with JS within a DIV container with a specific ID. I use custom JS to acomplish that:
Code
function x3_load_page(){
  $("#03-bulletpoints").load("content/custom/files/html/03-bulletpoints.html");
  
  $("#04-vertrauenssymbole").load("content/custom/files/html/04-vertrauenssymbole.html");
}
The content of the context looks like that:
Code
<!-- 03 - Bulletpoints -->

<div id="03-bulletpoints"></div>


<!-- 04 - Vertrauenssymbole -->

<div class="borderedHeader">
<h1>Bekannt von</h1>
<p></p>
</div>

<div id="04-vertrauenssymbole"></div>
When defining the comparison slider HTML within an external HTML file, the slider overlay is not shown as - I assume - is not recognized in the first place as the injection hasn't been done, yet.

So, I want to call the function which is doing that.

Thanks a lot!
 
User avatar
mjau-mjau
X3 Wizard
Posts: 13997
Joined: 30 Sep 2006, 03:37

Re: How to inject "folders" view within context and trigger comparison slider

01 Jan 2020, 00:32

Good solid questions to kickstart 2020. I believe we will add options to include custom html content before and after all modules (like the folders module) in a future release. For now, it would have be done by javascript ... I don't think we can copy the entire folders module INTO the content module, because of CSS styles and javascript. Instead, it would be rather easy to MOVE some html from your content, to below the the folders module.

1. In your page content section, add a div element with class name "folders-after", where you include all the content you want to move below the folders module.
Code
<div class="folders-after">My content to go <strong>below</strong> folders.</div>

2. Settings > Custom > Javascript, to find the element above, and then move it below folders.
Code
function x3_load_page(){
  var folders_after = document.getElementsByClassName('folders-after')[0];
  if(folders_after){
    var folders = document.getElementsByClassName('folders')[0];
    if(folders) folders.after(folders_after);
  }
}

3. Although the above does the job, you may need to add custom CSS styling for the copied object, which no longer belongs to context > content. For example margins, centering, max-width. Add to Settings > Custom > Custom CSS:
Code
.folders-after {
  margin: 20px auto 40px;
}
As for the comparison slider, the problem is that it is triggered by X3 on page load, in which case your external HTML has not yet loaded. Also, the native X3 funtion is minified and not supposed to be public, but you might be able to access it by triggering the function after your content is loaded:
Code
$("#03-bulletpoints").load("content/custom/files/html/03-bulletpoints.html", function() {
 Ki($('.content'));
});
 
User avatar
svenflock
Experienced
Topic Author
Posts: 34
Joined: 14 Oct 2019, 14:44

Re: How to inject "folders" view within context and trigger comparison slider

01 Jan 2020, 08:05

Thanks :-)

About the comparison slider:

Awesome! Triggering the Ki-function with the JS callback option did the trick :-). I have added it to all external calls where I am using the comparison slider.


About the after-folders part:

Nice trick :-). Your custom JS code works nicely and my content is moved after the folders view. I wrapped my code within a clone of the context CSS classes to get my original formatting back to life, i.e.:
Code
<div class="folders-after">
<div class="clearfix context small-12 large-10 small-centered columns separator title-normal narrow context-left-header-center">

...

</div>
</div>
I just have to take care that once I change layout of the context that I have to align the CSS classes for the after-folders part :-). 

Moving the DIV container down broke again the comparison slider (search for the header h1 "Zufriedenheit"). I tried to add the callback after folders.after(, <Callback> ) but it didn't fire. Is there another trick?


Further, the "toggle-content" feature (search for the header h1 "FAQ"). Clicking the "+" symbol gets me back to the header. There must be a JS function to call, too :-).

I know that I am bending the framework to the limits but there is always the main page which is "special" to all other content presented to the customer. I have done it in Wordpress an in Koken before. I don't like it very much because it is a lot of hacking :-). At least, I try to make it as nice as possible.

Talking about hacking: I had to used JQuery functions to inject external HTML files. Actually, this is something I would perform server-side with PHP. So, I tried it first but PHP tags have been ignored. Is there support for that? Or do you handle all of your backend stuff with JS only?

To make it even nicer :-): currently x3_load() and x3_page_load() call code that is executed for each page. I do only need it for the the "index" page. Is there something similar as in Wordpress to check if the page is the index page, e.g. IS_PAGE() or IS_HOME()?
 
User avatar
svenflock
Experienced
Topic Author
Posts: 34
Joined: 14 Oct 2019, 14:44

Re: How to inject "folders" view within context and trigger comparison slider

01 Jan 2020, 14:01

I cannot figure out the problem with the comparison slider. Here is my custom JS code.

I defined a function to inject my external HTML:
Code
function getPageContent(callback) {
  console.log("Inject external pages");

  $("#03-bulletpoints").load("content/custom/files/html/03-bulletpoints.html");

  $("#04-vertrauenssymbole").load("content/custom/files/html/04-vertrauenssymbole.html");

  $("#06-warum-ein-profi").load("content/custom/files/html/06-warum-ein-profi.html", function() {
 Ki($('.content'));
});  

  $("#11-testimonials").load("content/custom/files/html/11-testimonials.html", function() {
      setGoogleReviewColumnWidth(".eagr-reviews-layout-grid-item");
      setHeaderWidth();
    }
  );

  $("#13-kundenwert-erhoehen").load("content/custom/files/html/13-kundenwert-erhoehen.html");

  $("#14-video-testimonials").load("content/custom/files/html/14-video-testimonials.html");

  $("#15-zufriedenheitsgarantie").load("content/custom/files/html/15-zufriedenheitsgarantie.html", function() {
 Ki($('.content'));
});

  $("#16-oft-gestellte-fragen").load("content/custom/files/html/16-oft-gestellte-fragen.html");

  $("#17-ueber-mich").load("content/custom/files/html/17-ueber-mich.html");

  $("#18-kontaktformular").load("content/custom/files/html/18-kontaktformular.html");
  
  if(callback) callback(); 
}
I have defined another function to move the DIV container below the folders view:
Code
function movePageContent(callback) {
  console.log("Move DIV");
  /* Content unter "folders View" wieder ergänzen */
  var folders_after = document.getElementsByClassName('folders-after')[0];
  
  if(folders_after){
    var folders = document.getElementsByClassName('folders')[0];
    if(folders) folders.after(folders_after);
  }
  
  if(callback) callback(); 
}
During x3_page_load() I made sure that the functions are called sequentially as they should. I even made sure that the function only kicks in after the DOM has been loaded completely in the first place.
Code
function x3_load_page(){
  $( document ).ready(function() {
      console.log("DocumentReady");
      getPageContent( function() {
        movePageContent(function() {
            console.log("Add CSS classes");
            $( "#classesToAdd" ).addClass( "clearfix context small-12 large-10 small-centered columns separator title-normal narrow context-left-header-center" );
          }
        );
      }
    );
    }
  );
}
I have enriched all functions with console.logs to make sure of that.

The content of the index page has the inner DIV to find the place to inject the classes:
Code
<div class="folders-after">

<div id="classesToAdd">

...

</div>
</div>
What I would expect:
  1. DocumentReady
  2. Inject external HTML files
  3. Move DIV container
  4. Apply CSS classes to adjust the formats from the context
The result as expected from the console but not from the view (no slider is shown below "Zufriedenheit"):

Image

I made an experiment and let just executed the injection of the external HTML and executed manually the over commands from the debug console and there - the slider is shown. I don't get it. Why??

Image

It's like quantum mechanics: you observe the system and it behaves differently as unobserved :-).

Thanks a lot!
 
User avatar
mjau-mjau
X3 Wizard
Posts: 13997
Joined: 30 Sep 2006, 03:37

Re: How to inject "folders" view within context and trigger comparison slider

01 Jan 2020, 21:37

A lot of  issues here beyond what X3 is supposed to handle, especially if you are calling external content via JS and expect X3 functionality to work for your external content (loaded via jQuery). Although you might get the comparison slider working, it's a random function name, which will likely change on next release (because of the minifier mechansim), and for other native X3 functions, they might noe even be public.

As for the comparison slider, it's supposed to only trigger ONCE per page load, in which case it finds all the comparison-sliders, and initiates them. I haven't tested what happens if it triggers muiltiple times (which it clearly will do in your case). Could be harmless, but could make errors, just another pitfall.

To be able to do anything at all, do you at least have a link for me to check?

In regards to DocumentReady, this is a concept for loading traditional HTML websites. In X3, it will fire ONCE when first X3 page loads. It will NOT fire again when navigating the website, because pages are loaded and injected via AJAX using HTML5 pushstate. Furthermore, the x3_load_page function will only trigger after a page is loaded anyway, is it would be pointless with a DocumentReady inside.
 
User avatar
svenflock
Experienced
Topic Author
Posts: 34
Joined: 14 Oct 2019, 14:44

Re: How to inject "folders" view within context and trigger comparison slider

02 Jan 2020, 05:11

Sure,

you can find my homepage at:

https://ziin-hochzeitsfotograf-duesseldorf.de/

I can give you access to my self hosted Gitea repository or SSH/FTP access if you want to see the custom code.
 
User avatar
mjau-mjau
X3 Wizard
Posts: 13997
Joined: 30 Sep 2006, 03:37

Re: How to inject "folders" view within context and trigger comparison slider

02 Jan 2020, 05:14

And where on this page is there a problem?
 
User avatar
svenflock
Experienced
Topic Author
Posts: 34
Joined: 14 Oct 2019, 14:44

Re: How to inject "folders" view within context and trigger comparison slider

02 Jan 2020, 05:25

If you search for "Verzaubernde Momente", you will find the folders view. Below "Ihr habt Euch noch nicht satt gesehen?..." is the part which has been moved below the folders view with your code. Everything works with exception:
  • of the toggle-content" feature (search for the header h1 "FAQ"). Clicking the "+" symbol gets me back to the header
  • the comparison slider in the moved DIV (search for the header h1 "Zufriedenheit"). The wrapper is missing.
 
User avatar
svenflock
Experienced
Topic Author
Posts: 34
Joined: 14 Oct 2019, 14:44

Re: How to inject "folders" view within context and trigger comparison slider

02 Jan 2020, 05:32

The code I am running is posted above (helper functions, etc.)
 
User avatar
svenflock
Experienced
Topic Author
Posts: 34
Joined: 14 Oct 2019, 14:44

Re: How to inject "folders" view within context and trigger comparison slider

02 Jan 2020, 05:46

Code
Ki($('.folders-after'));
did the trick to get the slider back on the moved part. And indeed, as you suspected, running the JS function more than once wrapped the classes several times on the other code. I removed the callbacks.
Is Ki the already minified version of the function? If you release a new version: could you provide me with an updated name?

However, if I add the code to the x3_load_page, it is not executed:
Code
function x3_load_page(){
      getPageContent( function() {
        movePageContent(function() {
            console.log("Add CSS classes");
            $( "#classesToAdd" ).addClass( "clearfix context small-12 large-10 small-centered columns separator title-normal narrow context-left-header-center" );
            Ki($('.content'));
            Ki($('.folders-after'));
          }
        );
      }
    );
}
 
User avatar
mjau-mjau
X3 Wizard
Posts: 13997
Joined: 30 Sep 2006, 03:37

Re: How to inject "folders" view within context and trigger comparison slider

02 Jan 2020, 05:56

This is quite a project you got going. Looking at your code, first of all I should let you know that x3_load_page triggers for EVERY page on your website. It probably still works though, since in your case, if it doesn't find the javascript element references, the functions will just be ignored.

As mentioned in a previous post, X3 page plugins are internal functions that trigger on page load. If you are lazy-loading external html into the page after the page is loaded, plugins will not initiate. Although we might be able to locate the minified function names so you can re-trigger them AFTER your custom content is loaded, these minified function names might change in next release. Also, the functions are only meant to run ONCE on page content ... If you re-run the same function on the same content multiple times (after each of your "load" functions), I can't be sure this will work properly.

What I don't quite understand, what is the point of loading all these external HTML files? Of course I understand it might be easier for you to edit sections directly in separate html files, especially if you are using some HTML editor, but at production, you should glue everything together into the X3 page. Then you won't have problems with plugins.
 
User avatar
svenflock
Experienced
Topic Author
Posts: 34
Joined: 14 Oct 2019, 14:44

Re: How to inject "folders" view within context and trigger comparison slider

02 Jan 2020, 11:44

This is quite a project you got going. Looking at your code, first of all I should let you know that x3_load_page triggers for EVERY page on your website. It probably still works though, since in your case, if it doesn't find the javascript element references, the functions will just be ignored.
The project is only for the index page. All other pages uses only gallery and folders view as designed by X3 :-). That is why I am looking for something similar which exists in Wordpress, i.e. IS_HOME() or IS_PAGE() to only trigger the JS where required. I like performance and usually, I isolate code only to regions where it should be exposed to. Does X3 has a built in function to identify the name of the current page to be loaded?
Although we might be able to locate the minified function names so you can re-trigger them AFTER your custom content is loaded, these minified function names might change in next release. Also, the functions are only meant to run ONCE on page content ... If you re-run the same function on the same content multiple times (after each of your "load" functions), I can't be sure this will work properly.
I understand the risk and I have removed the ki-call to be compatible with future releases.
What I don't quite understand, what is the point of loading all these external HTML files? Of course I understand it might be easier for you to edit sections directly in separate html files, especially if you are using some HTML editor, but at production, you should glue everything together into the X3 page. Then you won't have problems with plugins.
I like clean code to develop, be able to easily diff between different versions. Further, some blocks contain a lot of HTML which took the parser some time to render in the backend.
I like your idea to "compile" everything for production back into the JSON. Can you recommend a tool for that, e.g. npm or Grunt?
After moving our the comparison slider from the external HTML files back to the main JSON, the slider worked (after adding the "content" class to the moved DIV container). Funny thing is that the "toggle content" works again. Thanks for the tip!!
Do you think it is possible for future versions to allow external editing of the JSONs (both pages and custom fields)? So the user provide HTML, CSS and JS files like in the custom folder but it is automatically merged by the backend back to the JSON?
 
User avatar
mjau-mjau
X3 Wizard
Posts: 13997
Joined: 30 Sep 2006, 03:37

Re: How to inject "folders" view within context and trigger comparison slider

02 Jan 2020, 23:19

I understand you wish to make modifications, and I have a lot of respect for those who take the time with this, as I have been in this situation myself with other websites as well as X3.
svenflock wrote:The project is only for the index page. All other pages uses only gallery and folders view as designed by X3 :-). That is why I am looking for something similar which exists in Wordpress, i.e. IS_HOME() or IS_PAGE() to only trigger the JS where required. I like performance and usually, I isolate code only to regions where it should be exposed to. Does X3 has a built in function to identify the name of the current page to be loaded?
Wordpress is actually a CMS where you build the website (via PHP), and this is different in your case since we are using Javascript. However, it's not too complicated since X3 adds unique body classes that represent the specific page. For example, the home page contains unique class page-index, and this can easily be checked in the page load script:
Code
function x3_load_page(){
  if(document.body.classList.contains('page-index')) {
    // home page stuff here
  }
}
svenflock wrote:I understand the risk and I have removed the ki-call to be compatible with future releases.
You could use them, but then you might need to re-identify their minified name after updates. The other option, is to trigger functions via the external plugin, but then you/we would need to write additional code for each plugin.

I guess in the future, there is no reason I couldn't make many functions public, so for example they could be accessed X3.cslider(), or even X3.update_page() to update all on page. A challenge here is that these functions are not meant to run multiple times on the same page, so that would require adapting all functions. Something to think about.
svenflock wrote:I like clean code to develop, be able to easily diff between different versions. Further, some blocks contain a lot of HTML which took the parser some time to render in the backend.
I like your idea to "compile" everything for production back into the JSON. Can you recommend a tool for that, e.g. npm or Grunt?
Understood. I don't have any suggestions on how to auto-compile your templates into the page.json file. My idea was, considering the challenges with lazy-loading html fragments, it might be worth manually adding your templates into the page from the panel, once you feel the page is complete. You also need to consider the fact that all your load() functions cause many additional load requests for the visitor when they arrive on the page. Probably harmless, but it's not optimal.
svenflock wrote:After moving our the comparison slider from the external HTML files back to the main JSON, the slider worked (after adding the "content" class to the moved DIV container). Funny thing is that the "toggle content" works again. Thanks for the tip!!
I can't explain this without studying the process in detail, but likely it's related to timing. If some element is moved before the X3 page functions trigger (which might be 1ms), those elements could be excluded (depending on context). If you for example added setTimeout() to the move function, the comparison slider would likely trigger correctly, and when it's moved, it's already working. The reason you have to add the "content" class is probably because the comparison slider runs inside the element with "content", while your slider was already moved outside.
svenflock wrote:Do you think it is possible for future versions to allow external editing of the JSONs (both pages and custom fields)? So the user provide HTML, CSS and JS files like in the custom folder but it is automatically merged by the backend back to the JSON?
Although there are JSON editors which allow intuitive editing of JSON fields (for example X3 page.json files), I don't see any logical way to be able to merge lots of data into a page.json. We could perhaps use some <!-- include filename.html --> which is rendered in PHP, but I don't see how this would apply for CSS or JS.
 
User avatar
svenflock
Experienced
Topic Author
Posts: 34
Joined: 14 Oct 2019, 14:44

Re: How to inject "folders" view within context and trigger comparison slider

03 Jan 2020, 17:30

Thanks for all your insights. The page class worked perfectly. I know that I try things at the frontend which is usually backend stuff I would perform with PHP. I tried using PHP tags but they have been ignored. So, I guessed, that's not an option :-).
I guess in the future, there is no reason I couldn't make many functions public, so for example they could be accessed X3.cslider(), or even X3.update_page() to update all on page. A challenge here is that these functions are not meant to run multiple times on the same page, so that would require adapting all functions. Something to think about.
That would be great. I know it's challenging to fulfil all functional and non-functional requirements of all customers (even more if they represent only edge cases). So thanks for having an open mind about that :-).