Coder Social home page Coder Social logo

moox / pjax Goto Github PK

View Code? Open in Web Editor NEW
1.4K 51.0 122.0 1.04 MB

Easily enable fast Ajax navigation on any website (using pushState + xhr)

License: MIT License

JavaScript 92.08% HTML 6.74% TypeScript 1.19%
ajax pjax pjax-request jquery-pjax pushstate navigation

pjax's Introduction

Pjax

Build Status.

Easily enable fast AJAX navigation on any website (using pushState() + XHR)

Pjax is a standalone JavaScript module that uses AJAX (XmlHttpRequest) and pushState() to deliver a fast browsing experience.

It allows you to completely transform the user experience of standard websites (server-side generated or static ones) to make users feel like they are browsing an app, especially for those with low bandwidth connections.

No more full page reloads. No more multiple HTTP requests.

Pjax does not rely on other libraries, like jQuery or similar. It is written entirely in vanilla JS.

Installation

  • You can link directly to the bundle:

    <script src="https://cdn.jsdelivr.net/npm/pjax@VERSION/pjax.js"></script>
  • Or the minified bundle:

    <script src="https://cdn.jsdelivr.net/npm/pjax@VERSION/pjax.min.js"></script>
  • You can also install Pjax from npm:

    npm install pjax

    Note: If you use this option, you will need to do one of the following:

    • Link a script tag to either pjax.js or pjax.min.js. E.g.:
    <script src="./node_modules/pjax/pjax.js"></script>
    • Use a bundler like Webpack. (index.js cannot be used in the browser without a bundler).
  • Or you can clone the repo and build the bundle from the source using npm:

    git clone https://github.com/MoOx/pjax.git
    cd pjax
    npm install
    npm run build

    and then link a script tag to either pjax.js or pjax.min.js. E.g.:

    <script src="./pjax.min.js"></script>

What Pjax Does

Under the hood, it's just ONE HTTP request with a pushState() call.

Pjax loads pages using AJAX and updates the browser's current URL using pushState() without reloading your page's layout or any resources (JS, CSS), giving a fast page load.

It works with all permalinks and can update all the parts of the page you want (including HTML metas, title, and navigation state).

In the case of browsers that don't support history.pushState(), Pjax gracefully degrades and does not do anything at all.

Additionally, Pjax:

  • Is not limited to one container, like jQuery-Pjax is.
  • Fully supports browser history (back and forward buttons).
  • Supports keyboard browsing.
  • Automatically falls back to standard navigation for external pages (thanks to Captain Obvious's help).
  • Automatically falls back to standard navigation for internal pages that do not have an appropriate DOM tree.
  • Allows for CSS transitions (animations) very easily.
  • Is only around 6kb (minified and gzipped).

How Pjax Works

  • It listens to every click on links you want (by default all of them).
  • When an internal link is clicked, Pjax fetches the page's HTML via AJAX.
  • Pjax renders the page's DOM tree (without loading any resources - images, CSS, JS, etc).
  • It checks that all defined parts can be replaced:
    • If the page doesn't meet the requirements, standard navigation is used.
    • If the page meets the requirements, Pjax does all defined DOM replacements.
  • Then it updates the browser's current URL using pushState().

Overview

Pjax is fully automatic. You don't need to change anything about your existing HTML, you just need to designate which elements on your page that you want to be replaced when your site is navigated.

Consider the following page.

<!DOCTYPE html>
<html>
<head>
  <!-- metas, title, styles, etc -->
  <title>My Cool Blog</title>
  <meta name="description" content="Welcome to My Cool Blog">
  <link href="/styles.css" rel="stylesheet">
</head>

<body>
  <header class="the-header">
    <nav>
      <a href="/" class="is-active">Home</a>
      <a href="/about">About</a>
      <a href="/contact">Contact</a>
    </nav>
  </header>

  <section class="the-content">
    <h1>My Cool Blog</h1>
    <p>
      Thanks for stopping by!

      <a href="/about">Click Here to find out more about me.</a>
    </p>
  </section>

  <aside class="the-sidebar">
    <h3>Recent Posts</h3>
    <!-- sidebar content -->
  </aside>

  <footer class="the-footer">
    &copy; My Cool Blog
  </footer>

  <script src="onDomReadystuff.js"></script>
  <script>
    // analytics
  </script>
</body>
</html>

We want Pjax to intercept the URL /about, and replace .the-content with the resulting content of the request.

It would also be nice if we could replace the <nav> to show that the /about link is active, as well as update our page meta and the <aside> sidebar.

So all in all we want to update the page title and meta, header, content area, and sidebar, without reloading styles or scripts.

We can easily do this by telling Pjax to listen on all a tags (which is the default) and use CSS selectors defined above (without forgetting minimal meta):

var pjax = new Pjax({
  selectors: [
    "title",
    "meta[name=description]",
    ".the-header",
    ".the-content",
    ".the-sidebar",
  ]
})

Now, when someone in a Pjax-compatible browser clicks an internal link on the page, the content of each of the selectors will be replaced with the specific content pieces found in the next page's content.

Magic! For real! There is no need to do anything server-side!

Differences with jQuery-pjax

  • No jQuery dependency.
  • Not limited to a container.
  • No server-side requirements.
  • Works for CommonJS environment (Webpack/Browserify), AMD (RequireJS) or even globally.
  • Allows page transitions with CSS animations.
  • Can be easily tweaked, since every method is public (and as a result, overridable).

Compatibility

Pjax only works with browsers that support the history.pushState() API. When the API isn't supported, Pjax goes into fallback mode (and it just does nothing).

To see if Pjax is actually supported by your browser, use Pjax.isSupported().

Usage

new Pjax()

Let's talk more about the most basic way to get started.

When instantiating Pjax, you can pass options into the constructor as an object:

var pjax = new Pjax({
  elements: "a", // default is "a[href], form[action]"
  selectors: ["title", ".the-header", ".the-content", ".the-sidebar"]
})

This will enable Pjax on all links, and designate the part to replace using CSS selectors "title", ".the-header", ".the-content", ".the-sidebar".

In some cases, you might want to only target some specific elements to apply Pjax behavior. In that case, you can do two different things:

  1. Use a custom CSS selector( such as "a.js-Pjax" or ".js-Pjax a", etc).
  2. Override Pjax.prototype.getElements.
    • Note: If doing this, make sure to return a NodeList.
// use case 1
var pjax = new Pjax({ elements: "a.js-Pjax" })
// use case 2
Pjax.prototype.getElements = function() {
  return document.getElementsByClassName(".js-Pjax")
}

var pjax = new Pjax()

loadUrl(href, [options])

With this method, you can manually trigger the loading of a URL:

var pjax = new Pjax()

// use case 1
pjax.loadUrl("/your-url")

// use case 2 (with options override)
pjax.loadUrl("/your-other-url", { timeout: 10 })

handleResponse(responseText, request, href, options)

This method takes the raw response, processes the URL, then calls pjax.loadContent() to actually load it into the DOM.

It is passed the following arguments:

  • responseText (string): This is the raw response text. This is equivalent to request.responseText.
  • request (XMLHttpRequest): This is the XHR object.
  • href (string): This is the URL that was passed to loadUrl().
  • options (object): This is an object with the options for this request. The structure basically matches the regular options object, with a few extra internal properties.

You can override this if you want to process the data before, or instead of, it being loaded into the DOM.

For example, if you want to check for a non-HTML response, you could do the following:

var pjax = new Pjax();

pjax._handleResponse = pjax.handleResponse;

pjax.handleResponse = function(responseText, request, href, options) {
  if (request.responseText.match("<html")) {
    pjax._handleResponse(responseText, request, href, options);
  } else {
    // handle non-HTML response here
  }
}

refresh([el])

Use this method to bind Pjax to children of a DOM element that didn't exist when Pjax was initialised e.g. content inserted dynamically by another library or script. If called with no arguments, Pjax will parse the entire document again to look for newly-inserted elements.

// Inside a callback or Promise that runs after new DOM content has been inserted
var newContent = document.querySelector(".new-content");

pjax.refresh(newContent);

reload()

A helper shortcut for window.location.reload(). Used to force a page reload.

pjax.reload()

Options

elements (String, default: "a[href], form[action]")

CSS selector(s) used to find links to apply Pjax to. If needing multiple specific selectors, separate them by a comma.

// Single element
var pjax = new Pjax({
  elements: ".ajax"
})
// Multiple elements
var pjax = new Pjax({
  elements: ".pjax, .ajax",
})

selectors (Array, default: ["title", ".js-Pjax"])

CSS selectors used to find which content to replace.

var pjax = new Pjax({
  selectors: [
    "title",
    "the-content",
  ]
})

If a query returns multiples items, it will just keep the index.

Example of what you can do:

<!DOCTYPE html>
<html>
<head>
  <title>Page title</title>
</head>
<body>
  <header class="js-Pjax">...</header>
  <section class="js-Pjax">...</section>
  <footer class="the-footer">...</footer>
  <script>...</script>
</body>
</html>

This example is correct and should work "as expected".

NOTE: If the current page and new page do not have the same amount of DOM elements, Pjax will fall back to normal page load.

switches (Object, default: {})

This is an object containing callbacks that can be used to switch old elements with new elements.

The object keys should be one of the defined selectors (from the selectors option).

Examples:

var pjax = new Pjax({
  selectors: ["title", ".Navbar", ".js-Pjax"],
  switches: {
    "title": Pjax.switches.outerHTML, // default behavior
    ".the-content": function(oldEl, newEl, options) {
      // this is identical to the default behavior
      oldEl.outerHTML = newEl.outerHTML
      this.onSwitch()
    },
    ".js-Pjax": Pjax.switches.sideBySide
  }
})

Callbacks are bound to the Pjax instance itself to allow you to reuse it (ex: this.onSwitch())

Existing Switch Callbacks

  • Pjax.switches.outerHTML: The default behavior, replaces elements using outerHTML.
  • Pjax.switches.innerHTML: Replaces elements using innerHTML and copies className.
  • Pjax.switches.replaceNode: Replaces elements using replaceChild
  • Pjax.switches.sideBySide: Smart replacing that allows you to have both elements in the same parent when you want to use CSS animations. Old elements are removed when all children have been fully animated (an animationEnd event is triggered).

Creating a Switch Callback

Your callback function can do whatever you want, but you need to:

  1. Replace the oldEl's content with the newEl's content in some fashion.
  2. Call this.onSwitch() to trigger the attached callback.

Here is the default behavior as an example:

function(oldEl, newEl, pjaxOptions) {
  oldEl.outerHTML = newEl.outerHTML
  this.onSwitch()
}

switchesOptions (Object, default: {})

These are options that can be used during content replacement by switches. For now, only Pjax.switches.sideBySide uses it. This is very convenient when you use something like Animate.css with or without WOW.js.

var pjax = new Pjax({
  selectors: ["title", ".js-Pjax"],
  switches: {
    ".js-Pjax": Pjax.switches.sideBySide
  },
  switchesOptions: {
    ".js-Pjax": {
      classNames: {
        // class added to the old element being replaced, e.g. a fade out
        remove: "Animated Animated--reverse Animate--fast Animate--noDelay",
        // class added to the new element that is replacing the old one, e.g. a fade in
        add: "Animated",
        // class added on the element when navigating back
        backward: "Animate--slideInRight",
        // class added on the element when navigating forward (used for new page too)
        forward: "Animate--slideInLeft"
      },
      callbacks: {
        // to make a nice transition with 2 pages at the same time
        // we are playing with absolute positioning for the element we are removing
        // & we need live metrics to have something great
        // see associated CSS below
        removeElement: function(el) {
          el.style.marginLeft = "-" + (el.getBoundingClientRect().width/2) + "px"
        }
      }
    }
  }
})

Note that remove includes Animated--reverse which is a simple way to not have to have a duplicate transition (slideIn + reverse => slideOut).

Here is some css that works well with the above configuration:

/*
  Note: If your content elements don't have a fixed width it can cause
  an issue when positioning absolutely
*/
.js-Pjax { position: relative } /* parent element where switch will be made */

.js-Pjax-child { width: 100% }

/* position for the elements that will be removed */
.js-Pjax-remove {
  position: absolute;
  left: 50%;
  /* transform: translateX(-50%) */
  /* transform can't be used since we already use generic translate for the remove effect (eg animate.css) */
  /* margin-left: -width/2; // made with js */
  /* you can totally drop the margin-left thing from switchesOptions if you use custom animations */
}

/* CSS animations */
.Animated {
  animation-fill-mode: both;
  animation-duration: 1s;
}

.Animated--reverse { animation-direction: reverse }

.Animate--fast { animation-duration: .5s }
.Animate--noDelay { animation-delay: 0s !important;  }

.Animate--slideInRight { animation-name: Animation-slideInRight }

@keyframes Animation-slideInRight {
  0% {
    opacity: 0;
    transform: translateX(100rem);
  }

  100% {
    transform: translateX(0);
  }
}

.Animate--slideInLeft { animation-name: Animation-slideInLeft }

@keyframes Animation-slideInLeft {
  0% {
    opacity: 0;
    transform: translateX(-100rem);
  }

  100% {
    transform: translateX(0);
  }
}

To give context to this CSS, here is an HTML snippet:

<!doctype html>
<html>
<head>
  <title>Page Title</title>
</head>
<body>
  <section class="js-Pjax">
    <div class="js-Pjax-child">
      Your content here
    </div>
    <!--
    During the replacement process, you'll have the following tree:

    <div class="js-Pjax-child js-Pjax-remove Animate...">
      Your OLD content here
    </div>
    <div class="js-Pjax-child js-Pjax-add Animate...">
      Your NEW content here
    </div>

    -->
  </section>
  <script>...</script>
</body>
</html>

history (Boolean, default: true)

Enable the use of pushState(). Disabling this will prevent Pjax from updating browser history. While possible, there is almost no use case where you would want to do this.

Internally, this option is used when a popstate event triggers Pjax (to not pushState() again).

analytics (Function | Boolean, default: a function that pushes _gaq _trackPageview or sends ga pageview

Function that allows you to add behavior for analytics. By default it tries to track a pageview with Google Analytics (if it exists on the page). It's called every time a page is switched, even for history navigation.

Set to false to disable this behavior.

scrollTo (Integer | [Integer, Integer] | False, default: 0)

When set to an integer, this is the value (in px from the top of the page) to scroll to when a page is switched.

When set to an array of 2 integers ([x, y]), this is the value to scroll both horizontally and vertically.

Set this to false to disable scrolling, which will mean the page will stay in that same position it was before loading the new elements.

scrollRestoration (Boolean, default: true)

When set to true, Pjax will attempt to restore the scroll position when navigating backwards or forwards.

cacheBust (Boolean, default: true)

When set to true, Pjax appends a timestamp query string segment to the requested URL in order to skip the browser cache.

debug (Boolean, default: false)

Enables verbose mode. Useful to debug page layout differences.

currentUrlFullReload (Boolean, default: false)

When set to true, clicking on a link that points to the current URL will trigger a full page reload.

When set to false, clicking on such a link will cause Pjax to load the current page without a full page reload. If you want to add some custom behavior, add a click listener to the link and call preventDefault(). This will prevent Pjax from receiving the event.

Note: This must be done before Pjax is instantiated, otherwise Pjax's event handler will be called first, and preventDefault() won't have been called yet.

Here is some sample code:

  var links = document.querySelectorAll(".js-Pjax");

  for (var i = 0; i < links.length; i++) {
    var el = links[i]

    el.addEventListener("click", function(e) {
      if (el.href === window.location.href.split("#")[0]) {
        e.preventDefault();

        console.log("Link to current page clicked");
        // Custom code goes here.
      }
    })
  }

  var pjax = new Pjax()

(Note that if cacheBust is set to true, the code that checks if the href is the same as the current page's URL will not work, due to the query string appended to force a cache bust).

timeout (Integer, default: 0)

The timeout in milliseconds for the XHR requests. Set to 0 to disable the timeout.

Events

Pjax fires a number of events regardless of how it's invoked.

All events are fired from the document, not the link that was clicked.

  • pjax:send - Fired after the Pjax request begins.
  • pjax:complete - Fired after the Pjax request finishes.
  • pjax:success - Fired after the Pjax request succeeds.
  • pjax:error - Fired after the Pjax request fails. The request object will be passed along as event.options.request.

send and complete are a good pair of events to use if you are implementing a loading indicator (eg: topbar)

document.addEventListener('pjax:send', topbar.show)
document.addEventListener('pjax:complete', topbar.hide)

HTTP Headers

Pjax uses several custom headers when it makes and receives HTTP requests. If the requests are going to your server, you can use those headers for some meta information about the response.

Request Headers

Pjax sends the following headers with every request:

  • X-Requested-With: "XMLHttpRequest"
  • X-PJAX: "true"
  • X-PJAX-Selectors: A serialized JSON array of selectors, taken from options.selectors. You can use this to send back only the elements that Pjax will use to switch, instead of sending the whole page. Note that you'll need to deserialize this on the server (Such as by using JSON.parse())

Response Headers

Pjax looks for the following headers on the response:

  • X-PJAX-URL or X-XHR-Redirected-To

Pjax first checks the responseURL property on the XHR object to see if the request was redirected by the server. Most browsers support this, but not all. To ensure Pjax will be able to tell when the request is redirected, you can include one of these headers with the response, set to the final URL.

DOM Ready State

Most of the time, you will have code related to the current DOM that you only execute when the DOM is ready.

Since Pjax doesn't automatically re-execute your previous code each time you load a page, you'll need to add code to re-trigger the DOM ready code. Here's a simple example:

function whenDOMReady() {
  // do your stuff
}

whenDOMReady()

var pjax = new Pjax()

document.addEventListener("pjax:success", whenDOMReady)

Note: Don't create the Pjax instance in the whenDOMReady function.

If you want to just update a specific part (which is a good idea), you can add the DOM-related code in a function and re-execute this function when the pjax:success event is fired.

// do your global stuff
//... DOM ready code

function whenContainerReady() {
  // do your container related stuff
}

whenContainerReady()

var pjax = new Pjax()

document.addEventListener("pjax:success", whenContainerReady)

FAQ

Q: Disqus doesn't work anymore, how can I fix that ?

A: There are a few things you need to do:

  • Wrap your Disqus snippet into a DOM element that you will add to the selector property (or just wrap it with class="js-Pjax") and be sure to have at least an empty wrapper on each page (to avoid differences of DOM between pages).

  • Edit your Disqus snippet like the one below.

Disqus snippet before Pjax integration

<script>
  var disqus_shortname = 'YOURSHORTNAME'
  var disqus_identifier = 'PAGEID'
  var disqus_url = 'PAGEURL'
  var disqus_script = 'embed.js'

  (function(d,s) {
  s = d.createElement('script');s.async=1;s.src = '//' + disqus_shortname + '.disqus.com/'+disqus_script;
  (d.getElementsByTagName('head')[0]).appendChild(s);
  })(document)
</script>

Disqus snippet after Pjax integration

<div class="js-Pjax"><!-- needs to be here on every Pjax-ified page, even if empty -->
<!-- if (some condition) { // eventual server-side test to know whether or not you include this script -->
  <script>
    var disqus_shortname = 'YOURSHORTNAME'
    var disqus_identifier = 'PAGEID'
    var disqus_url = 'PAGEURL'
    var disqus_script = 'embed.js'

    // here we will only load the disqus <script> if not already loaded
    if (!window.DISQUS) {
      (function(d,s) {
      s = d.createElement('script');s.async=1;s.src = '//' + disqus_shortname + '.disqus.com/'+disqus_script;
      (d.getElementsByTagName('head')[0]).appendChild(s);
      })(document)
    }
    // if disqus <script> is already loaded, we just reset disqus the right way
    // see https://help.disqus.com/developer/using-disqus-on-ajax-sites
    else {
      DISQUS.reset({
        reload: true,
        config: function () {
          this.page.identifier = disqus_identifier
          this.page.url = disqus_url
        }
      })
    }
  </script>
<!-- } -->
</div>

Note: Pjax only handles inline <script> blocks for the container you are switching.

Examples

Clone this repository and run npm run example, which will open the example app in your browser.

CONTRIBUTING

  • ⇄ Pull requests and ★ Stars are always welcome.
  • For bugs and feature requests, please create an issue.
  • Pull requests must be accompanied by passing automated tests (npm test). If the API is changed, please update the Typescript definitions as well (pjax.d.ts).

pjax's People

Contributors

behindthemath avatar christophwolff avatar compressed avatar coolhihi avatar dalebaldwin avatar darylteo avatar dependabot[bot] avatar gillesfabio avatar igierard avatar lacrioque avatar madx avatar mduheaume avatar mohamedboualleg avatar moox avatar oskarrough avatar pklada avatar robinnorth avatar rstacruz avatar thewatts avatar timtrinidad avatar tremby avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pjax's Issues

Download external scripts before executing inline JS?

The eval-script module is slick! But it doesn't address if the inline JS to eval is dependent on an external script that's loaded in the new DOM elements, e.g.

<script src="//somewebsite.com/coolThing.js"></script>
<script>coolThing();</script>

Would you be open to a pull request for that? Or is there a reason why you wouldn't want to do that?

Example Project?

Do you have an example project that shows, in the simplest manner possible, how to set up a webpage to use this project?

I am new to the pjax concept, as well as require.js, and there seem to be a lot of intermediate steps missing that describe how to set up your require calls in order to correctly load and call the pjax project's dependencies. A simple example project with two html pages showing the basic pjax loading functionality would answer all these setup questions.

Thank you.

Save scroll position in navigation history

Great project! You have a scroll option, which is useful for when NEW content is loaded.

However, if i do the following:

  • visited a link
  • scrolled down the page
  • clicked on a new link
  • viewed the new page
  • hit the back button

I am taken to the top of the page again. So i have to scroll all the way back down, trying to find where i was before.

When i click a link, can pjax not record my scroll position before loading the new content, then when i go back to a page, take me back to the same scroll position?

This would be very helpful.

Thanks very much.

Change way to handle .isSupported

Currently the way things are (shitty) done, the trick to "mock" api for unsupported browser is awful cause you can for eg use Pjax.switches.blah.
After refactor on testling branch, I need to do something else.
Like just add a .isSupported method & document the fact that every call & ref usages should be prefixed by this test ?

Resize / scroll triggered multiple times after a page transition

I have a page with multiple elements whose content pjax controls and each of those might use a different "switch" to swap the old content out for the new. After every page transition I have a bunch of scripts that handle how the new content is supposed to behave. Some of these need to also update on 'resize'.

The problem is that pjax triggers 'resize' and 'scroll' on every element "switch", so in my case would trigger resize & scroll 6 times for every page transition. The method responsible for that is: https://github.com/MoOx/pjax/blob/master/index.js#L72

My solution was to override the aforementioned onSwitch method with the following:

let switched = true;
Pjax.prototype.onSwitch = function onSwitch() {
    if (!switched) return;

    switched = false;
    // 'once' is implemented to fire event cb once and then de-attach
    once(window, 'pjax:complete', () => {
        Pjax.trigger(window, 'resize scroll');
        switched = true;
    });
};

This seems to work so far, but I am wondering whether there is a better way and/or whether pjax should handle triggering resize & scroll only once after a page transition internally.

loadContent doesn't match "just" <html>

Hey there,

I've been fiddling around with your library. Works well!

I found a small bug. This regex (https://github.com/MoOx/pjax/blob/master/src/pjax.js#L346) doesn't match <html>. It matches <html lang="en"> and a lot of other possibilities. But not plain old <html>!

Or maybe this (https://github.com/MoOx/pjax/blob/master/src/pjax.js#L349) should be if (matches && matches.length)

Thought I'd let you know.

Edit: Crap, let me rephrase this: String.prototype.match returns null if nothing is matched. It seems like that was what you were trying to do on that line. That's probably the issue.

analytics function doesn't send `t` object

Using v0.1.4, I'm getting this error:

                this.options.analytics = this.options.analytics || function(t) {
                    window._gaq && _gaq.push(["_trackPageview"]),
                    window.ga && ga("send", "pageview", {
                        page: t.url, # Uncaught TypeError: Cannot read property 'url' of undefined
                        title: t.title
                    })
                }

[Proposal] Pjax as EventEmitter?

At the moment, events are emitted via document using native dispatchEvent.

This (I think) causes issues if multiple instances of pjax are used.

Better to have Pjax as a EventEmitter emit its own events. This does increase the size of the library (4-5kb?).

[Release] 0.2.2

Hey @MoOx never done this before (npm/bower wise).

Can you tell me how to go about it? Do I just up the version numbers in package.json/bower.json and push a release tag or do I need to do other things?

I think now that the main library is "functional" we should push it out as is and then deal with issues as they come up.

Question: Different exiting/entering animations based on which link is clicked

Hi there!

I've been using jQuery Smoothstate to add custom animations to page transitions. Support has disappeared so I'm interested in replacing it. I looked into jQuery pjax but the lack of ability to allow a specified duration for CSS animations put me off and in turn, led me here. I've had a good read of your docs and it seems perfect, I just want to clear a few things up before I make the jump.

Is it be possible to change the exiting animations based on which link was clicked? I'm trying to have it feel like a horizontal slideshow so that I have left and right exiting/entering navigation. So if I click on the left link the screen animates out left and vice versa with the right link.

Further from this, I'd need to alter the animation on the following page, depending on the exiting animation. Does that make sense? This site is a good example (click the left and right links, they animate out and in according to which item you click.

Other than that I just need to be able to re-fire any JS that needs to be loaded once the page has loaded but I'm pretty sure you have that covered?

Finally, how closely are you planning to keep this to jQuery pjax, feature wise?

Many thanks,
Mike

No milestone usage

@darylteo I don't really like using milestone for small project like this one. Let's just merge PR and release (btw, I just came back and will release a new version asap).

Display that redirects were followed properly

When clicking a link which triggers a redirect (302 or whatever), PJAX disregards it and pushed the state with the link's URL.

I think it should push, in the state, the URL as sent in the response's header "Location". Also, probably worth looking at that header to check if the URL is external and if it is, then don't try to do PJAX on it.

Create demo pages...

with pjax disabled & a button to enable pjax with different effects TO SHOW THE POWER of this module (compared to jquery-pjax ?).

[Proposal] Manual invocation of Pjax.

A static method that allows invocation instead of relying on declarative options.

This would open the door to things like

  • dynamic links (instead of relying on href), could be based on runtime vars like time or attributes
  • non-a links
  • non-click (mobile taps, hovers, keypresses)
  • or any number of processing steps to yield a target url to load
  • different switch options

This method could also return a Promise, and puts us closer to $.pjax.

TypeError: Cannot set property 'firstrun' of undefined

Why I always get TypeError: Cannot set property 'firstrun' of undefined in the console. Am I doing something wrong?

Pjax({
    selectors: "main.main",
    switches: {
        "main.main": Pjax.switches.sideBySide
    },
    switchesOptions: {
        ".js-Pjax": {
            classNames: {
                // class added on the element that will be removed
                remove: "Animated Animated--reverse Animate--fast Animate--noDelay",
                // class added on the element that will be added
                add: "Animated",
                // class added on the element when it go backward
                backward: "Animate--slideInRight",
                // class added on the element when it go forward (used for new page too)
                forward: "Animate--slideInLeft"
            }
        }
    }
});

onSwitch is undefined - "this" is "window", not "pjax"

Pjax switch fail:  
TypeError: this.onSwitch is not a function(…)(anonymous function) @ vendor.bundle.js:277 

Stack Trace

module.exports.outerHTML (vendor.bundle.j…v=20160105:740)
(anonymous function) (vendor.bundle.j…v=20160105:722)
module.exports (vendor.bundle.j…v=20160105:390)
(anonymous function) (vendor.bundle.j…v=20160105:713)
module.exports (vendor.bundle.j…v=20160105:697)
Pjax.switchSelectors (vendor.bundle.j…v=20160105:174)
Pjax.loadContent (vendor.bundle.j…v=20160105:225)
(anonymous function) (vendor.bundle.j…v=20160105:272)
request.onreadystatechange (vendor.bundle.j…v=20160105:860)

Happens in switches.js outerHTML and innerHTML

Where is pjax.js located(bower or ZIP download) ?

Ok, this may be that I am a total idiot, cause I am a designer first and foremost, but I can't find the pjax.js file.

I've tried both the ZIP download and the bower installation, but there is no such file.

Tag v0.1.4

There's no git tags for v0.1.3 or v0.1.4.

Accessing the anchor that was clicked before pjax:send

Hi - wonder if anyone could help me, I need to somehow access the anchor that was actually clicked to trigger the pjax:send event. I figured I could do this by listening for the click on any but this event happens after the pjax:send. Any ideas?

Pjax.prototype.loadUrl() not working

Thanks for this great project!

I am attempting to implement a PJAX redirect with Pjax.prototype.loadUrl(). The actual code is

options = {
        elements: ['a', '.pjax'],
        selectors: ["#pjax"]
};
Pjax.prototype.loadUrl('/', options);

When I attempt to run call this, I get an error

TypeError: Cannot read property 'debug' of undefined
    at Object.Pjax.log (http://localhost:9000/bower_components/pjax/src/pjax.js:213:25)
    at Object.Pjax.loadUrl (http://localhost:9000/bower_components/pjax/src/pjax.js:408:12)
    at Scope.$scope.processForm (http://localhost:9000/scripts/controllers/getStartedController.js:11:22)
    at http://localhost:9000/bower_components/angular/angular.js:10567:21
    at http://localhost:9000/bower_components/angular/angular.js:18627:17
    at Scope.$eval (http://localhost:9000/bower_components/angular/angular.js:12412:28)
    at Scope.$apply (http://localhost:9000/bower_components/angular/angular.js:12510:23)
    at HTMLFormElement.<anonymous> (http://localhost:9000/bower_components/angular/angular.js:18626:21)
    at HTMLFormElement.jQuery.event.dispatch (http://localhost:9000/bower_components/jquery/dist/jquery.js:4409:9)
    at HTMLFormElement.elemData.handle (http://localhost:9000/bower_components/jquery/dist/jquery.js:4095:28) angular.js:9778
(anonymous function) angular.js:9778
(anonymous function) angular.js:7216
Scope.$apply angular.js:12512
(anonymous function) angular.js:18626
jQuery.event.dispatch jquery.js:4409
elemData.handle jquery.js:4095

I fixed this error by adding this.options = options to the very beginning of the loadUrl() function. However, after I fixed that error, I got a new error:

Pjax switch fail:  
TypeError {stack: (...), message: "Cannot read property '#pjax' of undefined"}
 pjax.js:432
(anonymous function) pjax.js:432
request.onreadystatechange pjax.js:395

So with this second error, it falls back to the window.location() option, which is not the behavior that I am looking for. I have messed around with the code in order to fix this error but I have yet to find a solution.

Attatch pjax events to injected links?

Should the pjax events attach to links that are injected through a previous pjax call by default or do you have to do something special to attach new pjax events to those newly inserted links? Currently, even though the links I am inserting follow the selector defined in elements, they are causing hard refreshes (not pjax events).

No X-PJAX header in request

It works, but the request header looks like it's missing the X-PJAX header, trying to setup my backend to just return body content for pjax request.

Readme example error

When I try to implement the demo in the readme (sideBySide switch) I get an error.

Pjax switch fail:  ReferenceError {stack: (...), message: "forEach is not defined"}
 pjax.js:431
(anonymous function) pjax.js:431
request.onreadystatechange

This error only happens with using sideBySide switch

switches: {
            ".js-Pjax": Pjax.switches.sideBySide
          }

using outerHtml or innerHtml does not throw this error. I'm using the latest Chrome browser.

Create a bookmarklet

This can be fun.
A bookmarklet to enable pjax on any website.
Just for the demo.

Example for jsScroll / infinate scroll

I see that you intend to add a few demos...

Would it be possible to add a demo which uses jsScroll or a similar infinite scroll add-on?

This is because i cannot see how to get this to work with your pjax.

Thanks very much!!

HierarchyRequestError

Hi, I tried using the latest version but it breaks on a HierarchyRequestError. I tracked down the bug:

Here you call trigger(document, ...), but trigger will add the element to the DOM if it doesn't have a parentNode (which document doesn't) here. The result is a call like document.body.appendChild(document) which breaks.

After downgrading to 0.1.4 this error disappeared.

there is something wrong when pjax running with google analytics.

thank you for this great pjax.

but I may found a bug when it run with google analytics.

options.analytics() didn't have any param. so ga("send", "pageview", {"page": options.url, "title": options.title}) got an error Cannot read property 'url' of undefined.

I fixed it by replaced with ga("send", "pageview", {"page": location.pathname, "title": document.title}).

Could you update the example? It's not working

I can't run the example code correctly.

The browser Console Shows (Firefox 43.0.1)

GET 
http://localhost:3000/pjax.js [HTTP/1.1 404 Not Found 2ms]
Document initialized: "http://localhost:3000/index.html" example.js:2:1
ReferenceError: Pjax is not defined

same behavior also in Internet Explorer 11.

I did the following commands:

git clone "https://github.com/MoOx/pjax.git"
cd pjax
node -v
v5.3.0
npm i
npm i -g serve
npm run example
> [email protected] example C:\Development\temp\pjax
> echo '
==> Open http://localhost:3000/example in your browser.'; serve .

'

     (nothing served yet)
cd example
serve .

After that, I opened http://localhost:3000/index.html in the browser window, opened the console window and saw the errormessage I already posted above ...ReferenceError: Pjax is not defined...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.