Coder Social home page Coder Social logo

dieulot / instantclick Goto Github PK

View Code? Open in Web Editor NEW
5.5K 5.5K 247.0 321 KB

InstantClick makes following links in your website instant.

Home Page: instantclick.io

License: MIT License

Makefile 1.25% PHP 11.05% CSS 1.25% JavaScript 72.30% HTML 14.15%

instantclick's Introduction

instantclick's People

Contributors

dieulot avatar kkirsche avatar maxov avatar pborreli avatar rison avatar ruricolist avatar wtfaremyinitials 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  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

instantclick's Issues

Document browser support?

Hi. I'm just wondering what we know about browser support. I've noticed there's an issue with Safari 7.0.1 and that looks to be the latest release. That's fine, sh- happens, I'm just curious about what can be expected.

Styles in the head are not loaded

The stylesheets, when included in the <head> are not loaded when the page is displayed. I had to include them in the <body> for them to be loaded.

Feedback on the loading indicator

You should also integrate the spinner from nprogress.

I'm testing out the master of IC with the progress bar and the progress bar becomes annoying and flashy when quickly navigating a site.

The spinner should be optional and separated from the progress bar.

P.S. you should separate the CSS from JS.

infiltrating chrome extensions

I am using chrome extension that puts its own dom elements. This library removes those elements after clicking anchor tags.

Inline CSS background-image does not get loaded

When I load a page with the following code on it:

<td style="background-repeat: no-repeat; background-position: 0px 7px; padding-left: 40px;background-image: url(/some/picture.png);">[..]</td>

then the td-background stays empty in the newest Chromium. Firefox seems to do OK.

Make Sure Scripts/CSS are Re-Loaded

Hello again,

I am aware of the change-event. However, I was wondering whether there is a way to automatically reload any other resources in the head-tag such as scripts and CSS (the scripts and stylesheets may vary from page to page)?

That way, this could be dropped-in to any website without having to manually call a ton of JavaScript. For example, when dropping this into one of my projects, I have to manually re-attach events to menus, lightboxes, galleries, tooltips, site-analytics and a range of other things.

I am not sure whether there is a clean way to parse and call the JS that is passed-back from the request, but I just thought I'd put it out there.

Cheers!

Functionality on slow pages / connection

When I am on a slow connection, I hover over a link, it starts to preload but when I click the link it is not preloaded yet (slow network or page) so nothing happens and the page look broken.

There should be a condition that when user clicks a link and the content is not yet preloaded, then a classic navigation to the target pagfe occurs.

it doesn't work after "document.write"

when I execute <script>document.write(somecode);</script> before <script src="/static/js/instantclick.js" data-no-instant></script> <script data-no-instant>InstantClick.init('mousedown');</script>

if doesn't work, it just show the content of the document.wrote.

Breaks Facebook like button

When loading site my Facebook like button works, but when navigating to a new page, I just disapears.
Any way to fix that?

.

.

Cache downloaded pages

When i hover multiple times over a link, it re-downloads the page. Thats not necessary, so you should cache allready downloaded pages.

preventDefault() in click handler is ignored

Without instantclick, if you bind a click handler to an element and in that handler, call e.preventDefault();, the browser does not follow that link. You can use that to provide non-javascript-fallback links while still having awesome javascript-dependent on-page features.

When using instantclick, hovever, the preventDefault() is ignored.

The problem is that instantclick's handler is called before the more specific handler (calling preventDefault), so isDefaultPrevented() still returns false for instantclick.

JS error in Magento and conflict between libraries

I put the integration of "instantclick" library the next project in Magento

http://www.cerebrum.com.br/demo_magento/index.php/

See it by clicking the logo is generated javascript error as image

http://www.cerebrum.com.br/diversos/Captura% 20of% 20the% 20tela% 202014-02-12% 2015:24:43. png

Also we see that the use of "instantclick" library is being generated conflict with the library "rstacruz_nprogress" because it is being displayed the charger but not being completed the same

http://ricostacruz.com/nprogress/

Breaks browsers back and forth

Mobile all is fine but on my laptop neither firefox or chromium can handle back and forth navigation with instantclick included. Is there a workaround?

InstantClick + jquery.history

This couple does not work together...
Error: Uncaught Error: History.js Adapter has already been loaded...
What to do? Is it possible to combine?

Instantclick Breaks Bootstrap Dropdowns

Ran into this issue today. On page navigation, Bootstrap-based dropdowns (on click) no longer work. They do work on the initial page, but after any kind of navigation takes place, they no longer appear when their navigation item is clicked..

My HTML structure looks like:

                    <li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown</a>
                        <ul class="dropdown-menu">
                            <li><a href="/foo">Foo Item</a></li>
                            <li><a href="/bar">Bar Item</a></li>
                        </ul>
                    </li>

I'm loading Instantclick via:

InstantClick.init("mousedown")

I believe this is an Instantclick issue, as the dropdowns worked previously and, as far as I can tell, Instantclick is being initialized correctly.

There is one error in the console, "Uncaught ReferenceError: orientation is not defined " from L533.

<noscript>

So when JS is turned off I display a message on my site.

The style script below should only be parsed by the browser when JS is turned off but I guess InstantClick forces the browser to parse it.

<noscript>
    <style type="text/css">header{margin-top:18px}body{margin-top:80px}</style>
    <div id="noJS">You have JavaScript disabled. JavaScript must be enabled for this site to function properly.</div>
</noscript>

I got around this bug by adjusting my CSS and removing that style tag altogether but I wanted to report this bug because it might annoy future devs.

Browser support

Hi,

could you please add a matrix of supported browsers with level of support? For example currently you have to read through How does it work and then the caniuse pushState matrix.

I think many clients would appreciate a simple matrix to see whether or not enough browsers (and thus market share on their website) are supported by instantclick to decide whether or not to use instantclick.

-- ooxi

NProgress

Hi,

Do you know if it's possible to configure http://ricostacruz.com/nprogress/ with InstantClick ?

The NProgress.start() can be made in the InstantClick.on "change", but how to trigger the end ?

Thanks.

Warn users who abuse GET

Some places like to abuse GET requests.

Imagine <a href='/logout'>Log Out</a> , the users hovers over it, it is instaclicked and the user is logged out. I think there should be a warning about this and possibly a way to opt out it of. (as in, a black list)

Maybe also a black list in the plugin itself to forbid things like:

    if([ "login","logout","delete","remove","update","save","submit"].some(x=> href.contains(x))){
         //early return
    }

Or in ES3 (No lambdas, no some,no contans)

    var arr = ["login","logout","delete","remove","update","save","submit"];
    for(var i = 0; i < arr.length; i ++){
        if(href.indexOf(arr[i]) !== -1){
             //early return
        }
    }

Some reasonable rate limiting

If you just absentmindedly move your cursor around a page for a few seconds, you can end up triggering 4 or 5 requests to the same URL. I get that you don't want "fetch once, cache forever" so that this works well with dynamic content. But firing off multiple requests to the same URL within the span of a second or two is just unnecessary.

I propose that there be a cache that holds on to pages for 5 seconds. If you need your site to be more dynamic than that, well, don't use this script.

wordpress plugin with options panel

i'd love to see a wordpress plugin for this js that enables users to adjust their settings as needed through an options panel. i just tried to set it up on one of my sites but it broke the display of my pages. i'm not code savvy enough to correct this issue on my own.

Preloading Self-links

While exploring instantclick, I was wondering if instantclick should skip preloading for links that point to the same page. Would this work better because chances of clicking on a link that reference to self is less than other links?

Custom selector

Would it be possible to use selectors instead of creating blacklist and whitelist?
I am working on a Wordpress site and I would like to add preload functionality just to some link (i.e. menu links, footer links, content).
Currently, my options are: blacklist all others links (admin bar, link to social networks) or whitelist the ones I am interested in preload.
In both cases I have to work on server-side to add the required attributes to the links.
Wouldn't it be easier to have a parameter to tell the script which links should have the preload? Something like

InstantClick.init('.menu a');
InstantClick.init('.hentry a');
InstantClick.init('.footer a');

This would definitely make easier selecting (and knowing) which links would have the preload capability.
I have seen the plugin uses

document.getElementsByTagName('a')

to retrive all links.
Perhaps

document.querySelectorAll(selector)

would be slower, but would allow more flexibility on the target links.
What do you think?

Flag to enable image caching

It would be great if instantclick could also start caching the images found in the body of the new document during the preload phase.

It could go through the new body find any img's, extract their src and load them hidden into the current dom.

I'm unsure if you could then rely on the browser cache when swapping the bodies, or whether you'd have to swap the img's in the new body with your caching images.

This should be a toggleable option to avoid using a large amount of bandwidth on image heavy pages (perhaps you whitelist the images?)

HTML Entities in Title-Tag Faulty

Hi there,

First of all: I am really liking this so far. Neat idea!

During some initial testing I came across this:
If you have a character such as "โ€“" in the title tag, it is normally displayed as "Website โ€“ Some Title". However, after loading a page with instantclick, it is shown as "Website โ€“ Some Title".

Anyhow, keep up the great work!

Script displays blank page when clicking links

Hello, I really want to use this script, but when I impliment it on my website, the entire body DOM element is removed and nothing is displayed when I click through to any link. All that remains in the DOM is the HTML, HEAD, and SCRIPT tags. Also, I get a JavaScript error in the browser console:

Uncaught TypeError: Cannot read property 'outerHTML' of null
InstantClick.init

Thanks for your help with this!! :)

css visited style is triggered

Love the idea, tested out instsantclick on a big site I manage. Chrome Version 32.0.1700.107 m.

I had to remove it though, since the "visited-style" was applied to all links instantclick preloaded. Even the one I ended up not clicking on. Is there a way around that?

I figured using the onmouse-trigger could partly solve it, but then I don't get the biggest speedups either :)

Conflict with underscore.js in Chrome 32

Can't isolate the issue, sorry. Removed all other scripts. Unpredictable behavior and unable to properly use in Chrome 32 OSX10.9. Wish I could help more.

Edit - got it working on a different server. Closing, as I cannot isolate. Sorry for the spam post.

Loading of page with textarea breaks rest of page

When I load a page that has a self-closed textarea on it, it seems as if the textarea is not properly closed, with the rest of the page's code is shown as content of the textarea. Example:

<textarea class="someclass" name="somename" id="someid rows="12" cols="500" /><!-- no closing tag, should be just an empty textarea -->

(it's an XHTML-page)

some small bugfixes and delay with clearTimer on onmouseout, prevents preloading to much urls

// InstantClick 1.0
// (C) 2014 Alexandre Dieulot
// http://instantclick.io/license.html

var InstantClick = function() {
var currentPathname = location.pathname
var pId = 0 // short for "preloadId"
var pHistory = {} // short for "preloadHistory"
var p = [] // short for "preloads"
var checkLinkFunction = function() { return true }

function removeHash(url) {
    if ( typeof(url)=='undefined' ) { return "" }

    var index = url.indexOf('#')
    if (index == -1) {
        return url
    }
    return url.substr(0, index)
}

function triggerEvent(name) {
    var event = document.createEvent('HTMLEvents')
    event.initEvent(name, true, true)
    dispatchEvent(event)
}

function debug() {
    return {
        currentPathname: currentPathname,
        p0: p[0],
        p1: p[1],
        pHistory: pHistory,
        pId: pId
    }
}

function instantanize(initializing) {
    var as = document.getElementsByTagName('a'), a, domain = location.protocol + '//' + location.host
    for (var i = as.length - 1; i >= 0; i--) {
        a = as[i]
        if (a.target || // target="_blank" etc.
            /* a.href.indexOf(domain + '/') != 0 || // another domain */
            a.href.indexOf('#') > -1 && removeHash(a.href) == removeHash(location.href) || // link to an anchor
            a.hasAttribute('data-no-instant') ||
            !checkLinkFunction(a.href.substr(domain.length), a)) {
            continue
        }
        a.className +=" preload-attached"; 

        a.addEventListener('mouseover', queue)
        a.addEventListener('mouseout', cancle_queue)
        a.addEventListener('click', click)
    }
    if (!initializing) {
        var scripts = document.getElementsByTagName('script'), script, copy, parentNode, nextSibling
        for (i = scripts.length - 1; i >= 0; i--) {
            script = scripts[i]
            copy = document.createElement('script')
            if (script.src) {
                copy.src = script.src
            }
            if (script.innerHTML) {
                copy.innerHTML = script.innerHTML
            }
            parentNode = script.parentNode
            nextSibling = script.nextSibling
            parentNode.removeChild(script)
            parentNode.insertBefore(copy, nextSibling)
        }
    }
    triggerEvent('page:change')
}

function cancle_queue(e) {
    if ( typeof (e.target.timeout ) != 'undefined' ) {
        window.clearTimeout( e.target.timeout  ); 
        e.target.timeout  = undefined; 
    }
}

function queue(e) {

    if ( e.target.className.indexOf(' preloading') > -1 ) {
        return 
    }
    console.log( "preloading: " + e.target.href );

    delay = 1000; 
    if ( typeof( localStorage['delay']) != "undefined" ) {
        delay = localStorage['delay'] ;
    }

    e.target.timeout = window.setTimeout( function() {
        preload(e.target.href, e.target)
    }, delay );

}

function preload(url , e_target) {



    var id = pId
    /* If the user has clicked on a link but the link's content
       has not been received yet, we preload another in parallel,
       so that if the first link is taking too much time, the user
       can exit by clicking another link, like in a normal browser. */
    if (p[pId].state == 'waiting') {
        id ^= 1
        // The ^ character is used to swap between 0 and 1
    }

    // set loading state
    e_target.className +=" preloading";

    p[id].state = 'preloading'
    p[id].e_target = e_target; 
    p[id].url = url
    p[id].body = false
    p[id].timingStart = +new Date
    p[id].timing = false
    p[id].xhr.open('GET', url, true)
    p[id].xhr.send()
}

function readystatechange(e) {
    var id = e.target.id

    if (p[id].xhr.readyState < 4) {
        return
    }

    var text = p[id].xhr.responseText

    p[id].timing = +new Date - p[id].timingStart
    // To debug, we know it has been preloaded if `timing` isn't false

    var bodyIndex = text.indexOf('<body')
    if (bodyIndex > -1) {
        p[id].body = text.substr(text.indexOf('>', bodyIndex) + 1)
        var closingIndex = p[id].body.indexOf('</body')
        if (closingIndex > -1) {
            p[id].body = p[id].body.substr(0, closingIndex)
        }

        /* Removing script[data-no-instant] */
        p[id].body = p[id].body.replace(/<script[^>]+data-no-instant[^>]*>[\s\S]*<\/script>/ig, '')
    }
    /* We're only getting the body element's innerHTML, not the
       element's attributes such as class etc.
       From a superficial look into it, it seems Turbolinks DOMify
       the body element so it's able to also get classes etc., and
       doesn't require an explicit body tag in the html. This
       should be explored later. */

    var titleIndex = text.indexOf('<title')
    if (titleIndex > -1) {
        p[id].title = text.substr(text.indexOf('>', titleIndex) + 1)
        p[id].title = p[id].title.substr(0, p[id].title.indexOf('</title'))
    }

    // turn to loaded state
    p[id].e_target.className +=" preloaded";


    pHistory[removeHash(p[id].url)] = {body: p[id].body, title: p[id].title}

    if (id == pId && p[pId].state == 'waiting') {
        display(p[pId].url)
    }
}

function click(e) {
    if (e.which > 1 || e.metaKey || e.ctrlKey) { // Opening in new tab
        return
    }
    e.preventDefault()
    display(e.target.href)
}

function display(url) {

    // different domain, load normal
    domain = location.protocol + '//' + location.host
    if ( url.indexOf(domain + '/') != 0 ) {
        location.href = url; 
        return; 
    }


    if (p[pId].url != url) {
        if (p[pId ^ 1].url != url) {
            //throw new Error('Clicked on a link without hovering on it first')
            location.href = url; 
        }
        else {
            pId ^= 1
        }
    }
    if (!p[pId].body) {
        p[pId].state = 'waiting'
        return
    }
    p[pId].state = 'displayed'
    document.body.innerHTML = p[pId].body
    document.title = p[pId].title
    if (p[pId].url != location.href) {
        if (p[pId].url.indexOf('#') == -1) {
            scrollTo(0, 0)
        }
        else {
            var elem = p[pId].url.substr(p[pId].url.indexOf('#') + 1)
            if (document.getElementById(elem) || document.getElementsByName(elem).length > 0) {
                elem = document.getElementById(elem) || document.getElementsByTagName(elem)[0]
                var offset = 0
                for (; elem.offsetParent; elem = elem.offsetParent) {
                    offset += elem.offsetTop
                }
                scrollTo(0, offset)
            }
            else {
                scrollTo(0, 0)
            }
        }
        history.pushState(null, null, p[pId].url)
    }
    currentPathname = location.pathname
    instantanize()
}

function init() {

    console.log('I init'); 

    if (!('pushState' in history)) {
        return
    }
    if (p.length) { // already initialized
        return
    }
    if (0 in arguments) {
        checkLinkFunction = arguments[0]
    }
    pHistory[removeHash(location.href)] = {body: document.body.innerHTML, title: document.title}
    for (var i = 0; i < 2; i++) {
        p[i] = {}
        p[i].xhr = new XMLHttpRequest()
        p[i].xhr.id = i
        p[i].xhr.addEventListener('readystatechange', readystatechange)
        p[i].url = false
        p[i].body = false
        p[i].title = false
        p[i].state = ''
        p[i].timingStart = false
        p[i].timing = false
    }
    instantanize(true)

    addEventListener('popstate', function() {
        if (currentPathname == location.pathname) {
            return
        }
        var loc = removeHash(location.href)
        if (!(loc in pHistory)) {
            location.href = location.href // Reloads the page and makes use of cache for assets, unlike location.reload()
            return
        }
        currentPathname = location.pathname
        document.body.innerHTML = pHistory[loc].body + '<script src="instantclick.js" data-no-instant></script>';
        document.title = pHistory[loc].title
        instantanize()
    })
}

return {init: init, debug: debug}

}()

console.log('lib loaded');
InstantClick.init();

blacklist class

hi! thanks for your effort, this project is awesome! ๐Ÿ‘
how would be possible to blacklist a determined class in all links of a given site?
lets say the class i want to blacklist would be named "ajax" ...

Images wrapped in anchor tag return undefined

Consider the issue below which returns undefined.

<a href="http://www.wbur.org/npr/260560847/senate-unexpectedly-moves-forward-on-unemployment-benefits">
<img src="http://media.wbur.org/pagebuilder/461196095_wide-147f0f90e194ad3a715b0f7c3c9f44ed59cfdccf_300.jpg"> 
</a>

Progressbar makes page load appear slower

Hi,

this is a UX regression you can see on instantclick.io: if you switch between already loaded pages the progress bar takes longer to fill than the page to swap.

I therefore recommend showing the progressbar not when the loading process starts but after 50ms. And never when switching between already loaded pages.

-- ooxi

Listen to onclick navigation

Really cool idea.

Would it be possible to listen to onclick ``addEventListenerand jQuery's.click(` navigation?

Here is a rough idea:

  • check for elements with data-href attributes and preload them too - that's a rather common scheme.
  • Check for elements with event listeners (either by overriding .addEventListener or jQuery's _data and checking the event listeners for code containing location( ?)= or window.location or location.href or location.reload( and if that's an address prefetch it

What do you think?

Javascript error on XHTML pages (incl. fix)

My apologies for not leaving a pull request. This line:

    while (target.nodeName != 'A') {

should be:

    while (target.nodeName != 'A' && target.nodeName != 'a') {

otherwise the script won't work on my (older XHTML-)pages.

Safari 7.0.1 OS X

When using the script on the above, on page changes the page will go white unless you refresh the page resulting in the following in console.

TypeError: 'undefined' is not an object (evaluating 'script.hasAttribute') line 117

Line 117: if (script.hasAttribute("data-no-instant"))

This is using the minified production and straight-up development version, error above is using dev version for clarity.

Miss first page view to google analytics

Although you've got a solution for GA:

< script src="instantclick.min.js" data-no-instant></script>
< script data-no-instant>
/* Google Analytics code here, without ga('send', 'pageview') */

InstantClick.on('change', function() {
ga('send', 'pageview', location.pathname + location.search);
});
InstantClick.init();
</ script>
But it still miss the first page view when user browse the page.

Progress bar customization

I like the idea of having a progress bar as you stated on your homepage's "What's next section. Just to add my 0.2 cents, it'd be good regardless of what you decide for the progress bar, for it to be highly customizable. Many people are using the spinners from the FontAwesome icon collection, so it'd be good if your script could accomodate this or other options. Also, it would be good to have onstart and onended event listeners to add/remove the progress bars/spinners.

I'm sure you're already thinking of this kind of stuff, but just wanted to chime in.

Thanks for making such a great plugin!

Not working on my site

I deployed the lib to http://www.kulman.sk according to instructions. There is no JavaScript error and the preloading does not work. I do not see any request on hover like on your demo site.

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.