0

I have a router set up with page.js that routes an index page (at '/'), project pages (at '/projects/<projectId>/' ), and static (image) files. It looks, basically, like this:

JavaScript

init: function () {
    page.base('/');
    // IndexPage
    page('', function (context, next) {
        displayIndexPage();
    });
    // ProjectPage
    page('projects/:project', function (context, next) {
        displayProjectPage();
    });
    // image files
    page(/^.+\.(jpg|png|gif|bmp)$/, function (context, next) {
        window.location = '/' + context.path;
    });
    // Exit the middleware
    page();
}

In my /projects/ folder, I have an .htaccess file with the following:

bash

    Options +FollowSymLinks
    RewriteEngine On
    # html5 pushstate (history) support
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_URI} !index
    RewriteRule ^.*$ ../index.html [QSA,L,NE]

The routing is generally working correctly. When I navigate to a static image file, .htaccess drops me outside of my single-page app, and the static file appears on screen. However, when I navigate back in my browser, I don't re-enter my app; URL changes, but there is no navigation, the image file remains on screen. No amount of popping or pushing state from there gets me back into my app.

I'm not totally sure I'm asking the right question here; not sure this is about serving static files as much as it is about routing a single-page app...I would be satisfied with any answer that allows page.js to pick back up on a popState.

EDIT: I'm exempting files from my RewriteRule because I need to serve them in the pages rendered by my app. However, when a visitor clicks on an image in a rendered page, I'd like the browser to simply display that image, with no markup.

laser
  • 1,388
  • 13
  • 14
ericsoco
  • 24,913
  • 29
  • 97
  • 127
  • Also, what am I doing wrong with my fenced code blocks? Why isn't syntax highlighting working here? – ericsoco Mar 02 '15 at 05:47
  • Oh, oops, SO doesn't support fenced code blocks. Too used to GH I guess. Thx @ariful-haque. – ericsoco Mar 02 '15 at 05:51
  • Your link to [Page.js](https://visionmedia.github.io/page.js/) isn't showing up because you forgot to prepend `https://`. – rgajrawala Mar 02 '15 at 05:52
  • Can you post an examples of a image url you are using? Not sure if you need the route for images because if the image file path exits, won't apache serve it directly bypassing the index.html (`RewriteCond %{REQUEST_FILENAME} !-f`) – Chris Gunawardena Mar 20 '15 at 00:39
  • @ChrisGunawardena This is the site: http://transmote.com/ Click into any project and then on any image, then browser-navigate back to see the problem. The intent of routing image files is to explicitly break out of the application and allow Apache to serve them directly; without routing to an application exit Apache never knows anything changed because everything is happening in page.js. – ericsoco Mar 21 '15 at 16:08
  • @ericsoco, I see what you mean, really strange problem. Just for the sake of debugging, do you have the same issue when you comment out the image files route? If I run on the console `window.location = "http://transmote.com/projects/vizthebay/vizTheBay01.jpg";` from "http://transmote.com/projects/vizthebay/" the back button works. – Chris Gunawardena Mar 22 '15 at 00:30
  • Commenting out the route makes no difference. I did just find an interesting thing though: if I start at the root, navigate to a project, refresh, click a photo, and then navigate back once (to the project), nothing happens, as before. But if I navigate back one more time, to the root, beyond the start of the session, page.js picks back up again and everything is fine. Seems that popping browser history doesn't trigger Apache rules while still within the current session...or something.... – ericsoco Mar 22 '15 at 01:00

2 Answers2

0

What is your expectation when the image links are clicked?

When routing for images, instead of changing the location, try doing something else with image. Load it via AJAX and append it to some element or so as per your expectation.

// image files
page(/^.+\.(jpg|png|gif|bmp)$/, function (context, next) {
    // Culprit
    // window.location = '/' + context.path;

    showImage('/' + context.path);
});

Edit

Use a non page.js link for images to allow browser to directly handle it. Example.

The jsfiddle link does not work well because of server side routing, but if you copy back to your server it will work.

  • My expectation is that the image file is shown in the browser in the browser's native image display format. This happens, but the user is now no longer in the page.js app. Navigating back, the URL *should* get picked up by Apache and there should be a redirect back to /index.html, where page.js should fire back up and route the viewer accordingly. Instead, the navigation event is just swallowed, nothing changes but the URL. – ericsoco Mar 21 '15 at 16:00
  • 1
    Ok, in that case for jpgs do not use page.js. Use direct links for images. Right now page.js changes the url once and your javascript changes it again adding 2 urls to history. When you click back from the image page you go to the page js route that redirects to the image again and you are in that loop. – Abhilash S Hebbar Mar 23 '15 at 12:19
  • I think you're right! I thought the `window.location()` call would step out of page.js but what you're describing sounds logical. I just need to figure out how to avoid page.js routing completely for a given URL pattern. Any tips off the top of your head? I can't test right now. Also, would be great if you could edit your answer to this effect so I can accept it if it works. – ericsoco Mar 23 '15 at 19:59
  • I don't think this example will work for my case; it works because it navigates to a URL/domain outside of what's set by page.base(), but my images are on the same domain as the rest of the routes. – ericsoco Mar 25 '15 at 01:52
0

If I understand what you want the end result to be, it can be done with a simple overlay containing your image that covers the entire window. Then catch the popstate event and remove the overlay. JQuery not required, only for brevity.

jsfiddle Note: your browser URL will not change, because the fiddle is inside an iframe.

Edit: Stackoverflow sets the origin to null, so check jsfiddle for the working example.

var url = 'http://indianapublicmedia.org/stateimpact/files/2013/01/apple-image-300x300.jpg';

$('.image').click(function () {
    $('body').append('<div id="overlay"><img src="' + url + '"></div>').appendTo('body');
    history.pushState(null, null, 'http://stackoverflow.com/imageURL');
});

window.onpopstate = function(){
    $('#overlay').remove();
};
#overlay {
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    z-index: 100;
    position: fixed;
    background: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<body>Some content here
    <img src="http://indianapublicmedia.org/stateimpact/files/2013/01/apple-image-300x300.jpg" class='image'>
</body>
user33946
  • 404
  • 6
  • 10
  • Thanks -- I may end up doing something like this (similar to what @Abhilash S Hebbar recommended above), but I'd prefer to just let the browser handle the images natively... – ericsoco Mar 22 '15 at 20:42