14

I'm developing a tumblr theme for my personal portfolio, but I'm encountering a serious problem in my work section, I want to create an horizontal slider effect, when I click next to see older posts,

like this:

http://tympanus.net/Tutorials/WebsiteScrolling/

I have this to define my nextPage, #section4 is where I have the posts of my work:

<!-- Next Page -->
{block:NextPage}
<div>
    <a id="next-button" href="{NextPage}#section4" class="next panel" style="position:relative; top:630px; left:1550px;">next</a>
</div>
{/block:NextPage}
<!-- / Next Page -->

Well, this is defined to open an other page:

"indexPage".tumblr.com#section4

when I click next it goes to:

"indexPage".tumblr.com/page/2#section4

Is there a way I can do this slide effect on my index page or at least give the illusion, that I'm making slide effect, when moving to other page?

Alex.K.
  • 3,342
  • 13
  • 38
  • 44
gn66
  • 635
  • 1
  • 10
  • 30
  • 3
    Don't you feel like you overbountied yourself? – nicael May 27 '14 at 16:27
  • 4
    No, I realy need an answer... :( – gn66 May 27 '14 at 16:28
  • I believe you'll need to have a one-pager website to achieve this effect. You can also check this out to see how to achieve different page transition effect http://tympanus.net/codrops/2013/05/07/a-collection-of-page-transitions/ – TheBokiya May 27 '14 at 16:33
  • to clarify, your work page is a tumblr page? (ie `site.tumblr.com/work`) or the posts of your tumblr are your works (ie: `site.tumblr.com/page/2` contains your older works but your theme has a front page and #section4 is where your posts are posted) or is it part of your theme (ie: `#section4` of the main theme)? – mfirdaus May 28 '14 at 01:33
  • hello! My work is on site.tumblr.com/#section4, I already have an vertical slider to switch between sections, but now i need an horizontal to switch inside section4, and load page/2 so i can do the slider – gn66 May 28 '14 at 09:47

2 Answers2

8

If I understand your question correctly, it is as serakfalcon mentioned but I'll add in tumblr specific points. You need to do three things specifically. I won't go into too much tumblr template codes and styling it and stick to these

  1. Loading the data dynamically
  2. Dynamically creating a new section/page
  3. Getting the navigation to work with new sections

Loading the data

This is actually the easy bit. For tumblr, as you mentioned, we can manually go to the next page by clicking the "next page" link. In tumblr this will look something like

{block:NextPage}
  <li></li><a href="{NextPage}" class="next-page static">{lang:Next page}</a></li>   
{/block:NextPage}

Since the pages are on the same domain, we can override the link to get the page using AJAX. We will be getting the raw HTML for this page. Which will include all the other parts of the page like the three other sections. There may be some tumblr template magic that we can do to limit this, but I'll consider that outside the scope. So how do we get the content specifically? We can feed the raw HTML into jquery for it to build document objects, and we can then select the content that has the post from there. So something like.

$(document.body).on('click',".static",function(e){ //delegated
    var xhr=$.get($(this).attr("href"),function(a){ //a is next page's HTML
        $loaded=$(a); //loaded now has a temporary object with next page's objects
        var postsHTML=$loaded.find("#posts").html() //contains posts we can embed
        //what to find depends on your template. I used the default id="posts"
    })
})

Creating a new section/page

Once we have the data, we now need to put the data into a new page. There's many ways on doing this but here's how I did it. First of all, I had a template for the new section. I put it in a script tag like so. I kind of like the semantics of doing it like this.

<script type="text/x-template" id="section-template">
    <div class="section">
        <div class="posts"></div>
        <ul class="nav">
            <li><a href="#section1">1</a></li>
            <li><a href="#section2">2</a></li>
            <li><a href="#section2">3</a></li>
            <li><a href="#section4">4</a></li>
            <li><a href="#" class="last-page">Back</a></li>
            <li><a href="#" class="next-page static">Next</a></li>
        </ul>
    </div>
</script>

With that done, whenever the data is loaded we can get the raw HTML from this, and create a the new elements by feeding it to jQuery again. We then append the posts to the div with class posts. We also get the next page link from the data to attach to the next-page link so that the earlier ajax call will work. If we can't find the next-page link, that means there's no more posts. So we can hide the next-page link. We'll also stop the existing link to load data through ajax and do the normal slidey thing. Finally we'll append the new section to the parent div of the sections, fix it's width and then transition to the new section.

$(document.body).on('click',".static",function(e){ //deferred
    e.preventDefault();
    var that=this //to refer inside $.get callback
    var xhr=$.get($(this).attr("href"),function(a){
        $(that).removeClass('static') //stop this link from loading again
        var $loaded=$(a)
        var next_section=$($("#section-template").html()); //make the new section
        var num_sections=$(".section").length + 1 //number of sections
        next_section.addClass(num_sections%2 ? "white" : "black") //consistency

        //find .posts in the new section and put the tumblr data in it
        next_section.find(".posts").html($loaded.find("#posts").html())
        //tumblr next page link. change according to template
        var next_link=$loaded.find(".static")
        if(next_link.length){ //if next link exists
            //attach href to next page link in new section
            next_section.find(".static").attr("href",next_link.attr("href"))
        } else { //no next
            //hide the next page link in new section
            next_section.find(".static").hide()
        }
        $("#horizontal-scroller").append(next_section); //append to body
        $("#horizontal-scroller").width(4000*num_sections); //resize body

        $('html, body').stop().animate({ //to the new section
            scrollLeft: $(next_section).offset().left
        }, 1000);

    }) //$.get

}) //click

Getting the navigation to work

I probably should append new links to the nav, but I guess to make it easier (and imagine how it look like with 40 pages) I decided to just use a "next page" and "last page" for the loaded content. The code is simple. For next page, if it's not .static, move to the next section and ditto last page. we'll delegate (technically, I'm using .on() but the docs on .delegate seemed easier to understand) it to the document body so that it works for all the new links.

So as a whole javascript/jquery will look something like

$(document.body)
.on('click','ul.nav a:not(.next-page):not(.last-page)',function(e){
    var $anchor = $(this);
    $('html, body').stop().animate({
        scrollLeft: $($anchor.attr('href')).offset().left
    }, 1000);
    e.preventDefault();
})
.on('click',".next-page:not(.static)",function(e){ //next page not static
    e.preventDefault()
    $('html, body').stop().animate({
        scrollLeft: $(this).closest(".section").nextAll(".section").offset().left
    }, 1000);
})
.on('click',".last-page",function(e){ //last page
    e.preventDefault()
    $('html, body').stop().animate({
        scrollLeft: $(this).closest(".section").prevAll(".section").offset().left
    }, 1000);
})
.on('click',".static",function(e){
    e.preventDefault();
    var that=this
    var xhr=$.get($(this).attr("href"),function(a){
        $(that).removeClass('static')
        var $loaded=$(a)
        var next_section=$($("#section-template").html());
        var num_sections=$(".section").length + 1
        next_section.addClass(num_sections%2 ? "white" : "black")
        next_section.find(".posts").html($loaded.find("#posts").html())
        var next_link=$loaded.find(".static")
        if(next_link.length){
            next_section.find(".static").attr("href",next_link.attr("href"))
        } else {
            next_section.find(".static").hide()
        }
        $("#horizontal-scroller").append(next_section); //append to body
        $("#horizontal-scroller").width(4000*num_sections); //resize body

        $('html, body').stop().animate({
            scrollLeft: $(next_section).offset().left
        }, 1000);
    }) //$.get
}) //click

Here's a live demo of it working. Didn't really bother with making the slides look nice but hopefully you found this helpful.

mfirdaus
  • 4,494
  • 1
  • 22
  • 26
  • I'm still implementing your solution. The first fase I thing its done, now it loads a new section on index page :D Problems I have: I already have a vertical slider, so i'm quite figuring it out how can i make both work cause for now this canceled my other one, so thing quite "explode" together. And the nex section its beeing loaded in the end of my page – gn66 May 30 '14 at 16:21
  • But for now everything is beeing integrated quite well. – gn66 May 30 '14 at 16:23
  • Hello, so i pretty much integrate all, just beautifully. So i'm having just a small problem, since I already had a vertical scroller, I added a different section: `.section2{ margin:0px; bottom:0px; width:4000px; float:right; height:1000px; text-shadow:1px 1px 2px #f0f0f0; ` and `script type="text/x-template" id="section-template">
    ` the only problem is that the post appears on the bottom of my page and not following the #section4 div, any soluctions? :X
    – gn66 May 31 '14 at 00:13
  • @gn66 would it be possible for me to see a page? I lack coffee so it's hard for me to parse this right now – mfirdaus May 31 '14 at 00:17
  • of course, but i have so manny problems yet :P thanks again for the reply. 1 problem: Everything only works on chrome ; 2 problem: Everything was made yet for my screen resolution so i have to adapt it, if you see thing small just increase scroll until the "+" from my nav matches the top of the piramid, you'll understand when u see it :) 3 problem: you may find a few bugs, just ignore them xD – gn66 May 31 '14 at 00:21
  • 1
    You have a big screen. Also I think I see the problem. The original webpage just appends stuff to body. And sections are floated, so since there is a vertical scroller, it renders near the bottom. I think rather than just the body, we should have a div that contains the horizontal scroller, and we should append to that. Not sure it'll break anything but I'll edit my template and answer and see if that will help. – mfirdaus May 31 '14 at 00:32
  • you're realy great dude, thanks very much for the help! – gn66 May 31 '14 at 00:35
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/54823/discussion-between-mfirdaus-and-gn66). – mfirdaus May 31 '14 at 00:45
  • I succeded just right now. Thankgs for your help, you don't need to waste more time here :) – gn66 May 31 '14 at 13:00
  • I succeded just right now. Thankgs for your help, you don't need to waste more time here :) Just one question, to go to previous page, how can i do that, as you could see i realy dont need navigation, but to use {PreviousPage} it simply reloads page – gn66 May 31 '14 at 13:16
  • hello again, do you have some tips for me to improve a bit this javascript, when i click next it freezes a bit, since it loads 7 posts, any ideas? :) – gn66 Jun 05 '14 at 22:13
  • @gn66 I guess get a loader gif ( maybe from http://ajaxload.info/ ) and show it on clicking next, and hiding it inside `xhr` callback. – mfirdaus Jun 06 '14 at 01:56
  • Can I just wait a bit before the slide occures, just 3 secconds the're a way to do that? – gn66 Jun 06 '14 at 18:17
  • @gn66 honestly that should work. no idea why it doesn't. new question perhaps? – mfirdaus Jun 08 '14 at 02:28
  • hello, are you there? – gn66 Jun 11 '14 at 08:23
5

Of course, everything has to happen on one page, or you can't exactly have the transition. So, either you load everything at run time, or you 'cheat' using AJAX.

alter the in-page javascript to the following:

function bindAnimation(event) {
            var $anchor = $(this);
            /*
            if you want to use one of the easing effects:
            $('html, body').stop().animate({
                scrollLeft: $($anchor.attr('href')).offset().left
            }, 1500,'easeInOutExpo');
             */
            $('html, body').stop().animate({
                scrollLeft: $($anchor.attr('href')).offset().left
            }, 1000);
            event.preventDefault();
        }

        $(function() {
            $('ul.nav').on('click','.getNew',getNewSection);    
            $('ul.nav').on('click','a',bindAnimation);
        });

This allows you to add a elements dynamically to the navs, and will attach an event listener to a new element we will use to get new content. Modify the nav menu so that the last element is something like:

<li class="getNew">New</li>

There. now clicking on that will load the new content. add this javascript code to your site above the previous javascript code:

window.newSectionBlack = false;
        window.SectionID = 4;
        function displaySection(data,textStatus, jqXHR) {
            $('#section3').after(data.html); //add the new section
            $('#'+data.id).addClass(newSectionBlack ? 'black' : 'white');
            newSectionBlack = !newSectionBlack; //style it consistently
            $('.getNew').before('<li><a href="#'+data.id+'">'+data.name+'</li>'); //attach a link to the new section to the menu
            $('body').css({width:4000*SectionID});
            $('#'+data.id+' ul.nav').on('click','a',bindAnimation); //bind scripts
            $('#'+data.id+' ul.nav').on('click','.getNew',getNewSection);
            $('#section1 > ul li:nth-last-child(2) > a').trigger('click'); //go to new
            SectionID++;
        }

function getNewSection() {
    $.ajax({
        type: "POST",
        url: 'LoadSection.php',
        data: {section:SectionID},
        success: displaySection,
        dataType: 'json'
   });
}

This javascript will POST a number corresponding to which section to load to a new file, LoadSection.php, which needs to respond with the HTML of the new section, the ID and name it should be called. loadSection.php can look like this:

<?php
header('Content-Type: application/json');
$send = array();
switch($_POST['section']) {
default:
    $send['html'] = '<div class="section" id="section'.$_POST['section'] .'"><h2>Section ' . $_POST['section'] . '</h2>
        <p>
            This is a new section loaded via AJAX, cool huh?
        </p>
        <ul class="nav">
            <li><a href="#section1">1</a></li>
            <li><a href="#section2">2</a></li>
            <li><a href="#section3">3</a></li>
            <li class="getNew">New</li>
        </ul>
    </div>';
    $send['id'] = 'section'.$_POST['section'];
    $send['name'] = $_POST['section'];
}
echo json_encode($send);

Now, your page can load content dynamically! Note, the nav bar should probably be restructured to be an absolute element that there's only one of instead of repeated on every page, and there's other stuff you can clean up but that's to be expected if you're taking a codrops example.

EDIT:

tumblr doesn't let you run server-side scripts on their server (makes sense), which are required for the AJAX method described above to work. However, there are a number of options available to you. 1) redirect the tumblr page to a site you control, and use the method described above. 2) use an iframe.

The iframe method could be done directly, which requires you to specify the urls of all the pages in advance (or at least they'll need to follow a predictable pattern), or indirectly using a AJAX script similar to the one above. I will demonstrate loading a direct iframe, I'm sure you can figure out the rest.

window.newSectionBlack = false;
window.newSectionID = 4;

function getNewSection() {
    $('#section3').after('<div class="section" id="section'+newSectionID+'"><h2>New Section</h2>
        <iframe src="yourtumbrsite.com></iframe>
        <ul class="nav">
            <li><a href="#section1">1</a></li>
            <li><a href="#section2">2</a></li>
            <li><a href="#section3">3</a></li>
            <li class="getNew">New</li>
        </ul>
    </div>
'); //add the new section
            $('#section'+newSectionID).addClass(newSectionBlack ? 'black' : 'white');
            newSectionBlack = !newSectionBlack; //style it consistently
            $('.getNew').before('<li><a href="#section'+newSectionID+'">'+newSectionID+</li>'); //attach a link to the new section to the menu
            $('body').css({width:4000*newSectionID});
            $('#'+data.id+' ul.nav').on('click','a',bindAnimation); //bind scripts
            $('#'+data.id+' ul.nav').on('click','.getNew',getNewSection);
            $('#section1 > ul li:nth-last-child(2) > a').trigger('click'); //go to new
            newSectionID++;
}
serakfalcon
  • 3,353
  • 1
  • 19
  • 33
  • Hello, I implemented this, but unfortunately Its not working, I'll continue to try because perhaps I'm not ajusting your code correctly. Thanks for the anwer, if everything works just fine i'll accept it. Do you have a gmail account so we can chat? – gn66 May 28 '14 at 09:56
  • I tested the code and made sure it works. The code assumes that you can send anything over. If you're loading from a different page (that you don't have control over), you may want to use an iframe instead, which you could either implement directly (by replacing the AJAX call, inserting the iframe link) or indirectly using the php page via the AJAX method I wrote. – serakfalcon May 28 '14 at 10:13
  • 1
    I'd prefer communicating on stackoverflow if that's ok – serakfalcon May 28 '14 at 10:15
  • Ok, I'll continue to try to implement this in tumblr, I already have a vertical slider, so I have to ajust things a bit. I'll post here when i succeend thanks. – gn66 May 28 '14 at 10:16
  • Ok, did you experiment that in tumblr. I'm realy not succeeding. If i show you the code can you implement your soluction plz, So then I can see what changes you did and i can learn with it. thanks again. – gn66 May 28 '14 at 16:09