www.webdeveloper.com
Results 1 to 13 of 13

Thread: New plugin - History API

  1. #1
    Join Date
    Jan 2011
    Location
    Munich, Germany
    Posts
    237

    New plugin - History API

    Hello all,

    I've written this new plugin, which encapsulates the HTML5 History API:

    http://4nf.org/history/


    What do you think?


    Thanks in advance and kind regards

  2. #2
    Join Date
    Jan 2011
    Location
    Munich, Germany
    Posts
    237
    In this context, I have also created this GIST:


    A jQuery encapsulation of the HTML5 History API


    Any feedback of any sort?

  3. #3
    Join Date
    Jan 2011
    Location
    Munich, Germany
    Posts
    237

  4. #4
    Join Date
    Jul 2008
    Location
    urbana, il
    Posts
    2,787
    what about firing scripts and page-specific CSS? does $().ready() fire again when the fake page loads happens?

  5. #5
    Join Date
    Jan 2011
    Location
    Munich, Germany
    Posts
    237
    Hi rnd_me,

    the easy bit first - no JQuery "ready" does not get fired again.
    Instead, there is functionality for a callback function and/or bespoke event that is triggered on content div load.

    Thanks for having such a profound look at everything!

    Sure, I still have to integrate "Balupton's" script-handling or even improve on it.

    CSS's are a tough one. There is the current possibility to include them all on initial page load (i.e. everywhere) - that's what I'm doing on http://4nf.org/ and the (German) demo page http://www.oeko-fakt.de/.
    If you can think of something more elegant at a conceptual level - I'm not lazy and would be willing to go to great lengths, if the concept is right. Balupton seems to have no handling for CSS's at all and there are hardly any comments in this respect on his Gist.

    I take your valuable feedback very seriously and have forwarded the question to forum.jquery.com (see above link)

    It must be emphasised though, that the Gist is only applicable to rather simple site architectures. What you're doing will (probably) be too sophisticated for the thing to handle.

  6. #6
    Join Date
    Jul 2008
    Location
    urbana, il
    Posts
    2,787
    i am asking about the parts that got me stuck trying to implement the same kind of thing, but for any existing site, without modification. In theory, i belive it IS possible to do for ANY site with
    1. consistent page structure
    2. links to every internal page

    using a CMS or event dreamweaver templates basically ensures both criterion are met, so many sites, and most professional ones should be "ready to go"

    the snags i hit:

    1. broken links
    2. per-page CSS
    3. scripts not re-firing
    4. attempts to re-fire scripts led to build-up; a plugin on one page stays loaded for every page thereafter, and safely dismantling any and all script is futile.



    i do believe that with enough research, to problem can be defined and contained. I started to reverse-engineer jQuery's event structure, and there are in-memopry remnants of some $(function(){})-type code. I think if we could modify jQuery to "hold on" to every ready() call it it encountered, we would be abler to playback the proper page load events at the right time. The worst-case would be forcing manual page reload on problem pages. The only hard part is figuring out when that hard-load is required.


    I had quite a bit of things working. I used a bookmarklet to inject into any site, spider the <a> tag's hrefs, ajax the unique list of local URLs, remove any two identical lines (\n) in the source html and css of all pages to save space, deflate() the remainder, and store it in localStorage. I was getting a 500kb site (css+html+js) queezed down about 48kb of deflated garbage. The page load performance was phenomenal; i could see the page draw before i heard my mouse click. the other nice thing about have the whole site in ram is that searches are instant.

    I got pulled into other projects, but have since opened up a little time in my day-to-day to play with next gen delivery ideas such as these. Please share any ideas or or postulations about how to detect those load events. keep up the good work!

  7. #7
    Join Date
    Jan 2011
    Location
    Munich, Germany
    Posts
    237
    Hi rnd_me,

    Thanks for the overwhelming reply!

    I agree: the most elegant and perfect jQuery plugin would ideally just allow you to call the given interface generically and always work intelligently
    - on any site that fulfills the criteria you mentioned. That would be absolutely awesome!

    Boy, I would readily spend months on this, to get it working properly, given that the underlying design is sound.
    Thanks for taking your precious time to participate in the development!
    (I've got plenty of time at the moment, because I'm on a long professional leave of reconvalescence)

    Just wondering, would you be prepared to participate on the forth-development of the above Gist at GitHub?
    That's a nice and centralised platform for collabaration and maybe some other developers might join in, maybe even "Balupton", if he's got the time.
    I guess the guy didn't have the time to forth-develop the Gist because he's pursuing other projects.
    Just quickly checked and couldn't find your own profile at GitHub, but you seem to have mentioned GitHub in another thread, afaic remember.

    Wonderful, that you regard this as "next gen" development. I find it very promising, too, and would like to improve it as much as possible, even if it would be alright
    if the plugin is only used for very simple sites, of which there are tons anyway.

    Now to the technical bits:

    - Broken links -> I chose to delegate the hard work to the external "urlinternal" plugin for generically checking whether a link is internal, instead of doing my own dodgy link handling.
    If the link is broken beforehand - GIGO, I suppose?
    - per page CSS -> maybe you've got an idea on this or even experience. Really tricky would be page-specific CSSs that are mutually exclusive across the site?
    Otherwise theoretically manageable. (edit - see pseudo-code design of the "Script Remembering Handler" below, which could also handle CSS's along the way)

    - scripts not re-firing -> in one incident here: http://www.oeko-fakt.de/produkte/ (see table that pops up after selecting anything on the combo-box) I opted to hack into the respective JS and instead of wrapping the salient master code in ".ready()", we wrapped it in a function that get's called in the callback section of the plugin. It works, but is not exactly elegant.
    Educating people to do this would be awkward and make the procurement of the plugin less attractive for complex jQuery or otherwisely dynamic site. Now, my first and intial idea was to re-trigger ".ready()" and the whole associated (now internal) ReadyList manually, because that would be nice and generic and one could do without tampering the other jQuery code.
    But after some basic research and looking at some highly-rated threads at "stackoverflow", it seemed that that route once was viable, but in the later jQuery versions has been suppressed.
    Now, the readylist is not exposed anymore, cannot be tampered with and re-triggering ".ready()" has no effects at all, because it is "called once and only once".

    An idea would be to go lower-level in the DOM handling, so to say "beneath" jQuery and trick the browser into refiring the low-level DOMReady and ideally anything subsequently like jQuery's ".ready()" (along with the whole ReadyList) - maybe I'll research that one a bit more, or raise a dedicated thread in forum.jquery.com.

    Balupton's Gist used to be and still is popular and being used. For your convenience, I can quickly describe in pseudo-code what he has offered as a solution to the challenge:

    - AJAX pull gets the whole HTML of target page
    (- in between, he caches this away with a neat regular expression -> by the way, it might be possible to cache away the CSS references on this pass, too)
    (- this is in order to dump it successfully into the jQuery selector in it's entirety, which would otherwise fail)
    (- he then later on pulls back all script inner texts)
    - Re-engineers the script tags, attached to the content div along with their inner texts.
    - In most cases, they probably fire correctly, although there also has been criticism in the comments section

    Why, I'm hesitating to procure this 1:1 is because it seems that this is a bit redundant?
    Even if it works in most cases and requires very litte JS code, I think it's somewhat run-time superfluous because the common JSs ought to be in memory anyway,
    as only the content div is loaded dynamically. The entire original <head> for example, not to mention other common parts of the page should still be there??
    (especially nasty if some script doesn't appreciate being loaded several times, apart from the waste of run-time)

    In my opinion, the better algo would be to do something like a brief and generic delta-analysis of which scripts (and potentially CSS's, too) are to be loaded additionally, instead?
    Does jQuery offer something like a UNIX "filecmp" (i.e. FileCompare) on plain text sections? After all, in my algorithm, I've got the current page at my disposal and the target page, too, at the same time. It would be the differences/deltas that would require attention...

    <QUOTE>4. attempts to re-fire scripts led to build-up; a plugin on one page stays loaded for every page thereafter, and safely dismantling any and all script is futile.</QUOTE>

    We've talked about the first part of this sentence above - do you reckon a generic way for re-firing the actual event could be performed somehow?
    The second bit is the really hard part. How do you unload or at least disable page-specific scripts? Must admit, I haven't even thought about that, because it seems to be the usual case, that a resident script is just idle, when superfluous, but does not interfere. But I get your point - an entire jQuery plugin that remains resident across AJAX calls can lead to really funny results, surely.
    Maybe I'll raise a thread on this topic, too, at forum.jquery.com.

    If we're being nice and thorough, and really ambitiuos, I think the ideal solution would require it's own rather intelligent object, that handles these jobs.
    Here's the pseudo-code at the highest level that comes to my mind:

    - On "click" the object does a delta-analysis of target page scripts, against the current page's ("filecmp").
    - It loads them in after target div injection.
    - It remembers them (!)
    - On subsequent "click" or "popstate", it unloads them again

    (actually the last step should be performed before injection, just starting with an empty memory)

    As you mentioned, if, generically speaking, there is an exception/error along the way, that can't be gracefully descended, an escape to a hard page refresh is possible.
    (along with priorly logging the error to the console)

    It's very interesting to read about the project you put so much effort into. I'm glad to here, that the visible result was promising and you could see the potential advantages.
    Did you also attempt to engineer a generic tool (independent of web-pages). Or was it specific to the web page?
    Did you use Balupton's excellent "history.js" along with the "History API"?


    Would be great to here from you again, and I really cherish your profound professional experience!
    (btw thanks very much for all the various support in this forum in the past...)
    (please give me a quick hint, whether you'd be prepared to participate centrally at the development of the Gist.
    Be it only one or a few comments along the line - that would be invaluable)

    To sum it all up, in terms of research / feasibility studies the issue I'm currently thinking about most, is how to re-trigger ".ready()", be it at lower level.
    It really ought to be one of the most frequently asked DOM related questions??
    What do you think about that point?

    (again, if you agree it's a good idea, I'll be happy to raise a dedicated thread, after doing some exhaustive research on the web, whether there is a workaround or similiar)


    Talk to you soon and kind regards

  8. #8
    Join Date
    Jul 2008
    Location
    urbana, il
    Posts
    2,787
    i don't use or know that much about jQuery, but this SEEMS to work:

    Code:
    <!DOCTYPE html>
    <html>
    <head>
    	<title>js ready grabbing</title>
    	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    
    
    <script src="http://atlas.illinois.edu/_includes/scripts/jquery.js" type="text/javascript"></script>
    <script>
    (function($$){
      $$.events=[];
    
     var $=function $(v){ 
        if(typeof v==='function'){
      	$$.events.push(v);
        }; 
        return $$.apply( this, arguments);
      }//end $();
    
      for(var it in $$){if($$.hasOwnProperty(it)){  $[it]=$$[it];  }}
     
      $.prototype=$$.prototype;
    
      var ready=$.ready ;
    
      $.ready=function(v){ $$.events.push(v); return ready.apply(this, arguments); };
    
      self.$=$; 
     jQuery=$;
    }(jQuery));
    
    
    </script>
    <script src="http://www.atlas.illinois.edu/_includes/scripts/jquery.ui.js" type="text/javascript"></script>
    <script src="http://www.atlas.illinois.edu/_includes/scripts/jquery.cookie.js" type="text/javascript"></script>
    <script src="http://www.atlas.illinois.edu/_includes/scripts/jquery.scrollto.js" type="text/javascript"></script>
    <script src="http://www.atlas.illinois.edu/_includes/scripts/jquery.localscroll.js" type="text/javascript"></script>
    <script src="http://www.atlas.illinois.edu/_includes/scripts/jquery.prefbox.js" type="text/javascript"></script>
    <script src="http://www.atlas.illinois.edu/_includes/scripts/jquery.modal.js" type="text/javascript"></script>
    <script src="http://www.atlas.illinois.edu/_includes/scripts/jquery.lightbox.js" type="text/javascript"></script>
    <script src="http://www.atlas.illinois.edu/_includes/scripts/jquery.crossfade.js" type="text/javascript"></script>
    <script src="http://www.atlas.illinois.edu/_includes/scripts/jquery.validate.js" type="text/javascript"></script>
    <script src="http://www.atlas.illinois.edu/_includes/scripts/jquery.metadata.js" type="text/javascript"></script>
    <script src="http://www.atlas.illinois.edu/_includes/scripts/atlas.js" type="text/javascript"></script>
    <script src="http://www.atlas.illinois.edu/_includes/scripts/iepngfix_tilebg.js" type="text/javascript"></script>
    
    
    </head>
    <body>
      
    <div class="service-request">testing 123</div>
    <button onclick="retest()">retest</button>
    
      
    
    <script type='text/javascript'>
    
    function retest(){
      document.body.innerHTML='<div class="service-request">testing 123</div><button onclick="retest()">retest</button>';
      $.events.map(function(event){event.call($,{'type': 'ready'});});
      alert(document.body.innerHTML);
    }
    
    </script>
    </body>
    </html>
    it's a trivial example, ready()'s code calls $.wrap() around ".service-request", so this shows that at least some, if not all, ready events can be captured. sorry i don't have time today for a more concreate example, hopefully you can get the idea and run with it.

    cleaning them up is another problem, as is firing the right ones at the right time. You could use the url of the page to spec the collection of ready()s it needs. you would want to use an object {url: [ready()s]} instead of just [ready()s].

    still, this looks promising and the code above shows it may be possible. I didn't extensively test, but i don't see any throws, and the code i did try worked like a charm. kick the tires and let me know what/any problems arise from this jQuery hijacking.


    i don't really want to build a tool that needs jQuery, i prefer to "go native". I would be willing to help build a universal tool that plays well with jQuery but doesn't require it.


    i had considered this a big 'ace up my sleeve', by with the aim of helping others, i'll go ahead and dump the code i had below. i've been swamped lately. My biggest frustration with the code might be solved by the snip above, so perhaps this is the wrong time to give it away, but you seem enthusiastic, so let's go for it!


    i don't really have time to document it all right now. there are some comments. feel free to ask about anything that's confusing, and i'll get back to you.

    note that clientIO.lut is and object of all the page data, the key is the page url.


    it's at http://www.danml.com/magicio.js , may it serve you well.


    there are many non-content things the script does that i forgot about, <html>'s class, body's class, other attribs, images, favicons, rss feeds, etc. if nothing else, perhaps some of the pieces, snippets, and concepts can help you code a bullet-proof version.

    i was going to take this one step further. since all the meta gathering is done on string HTML processing instead of via the dom, the code easily runs on server-side javascript. one idea i had was to make a single script tag pass the root url to a node.js script, which itself would then spider the site, gathering all the html, css and js, doing the crunching, and delivering a json(p) bundle to the client containing the entire site. The next visitor could load that entire bundle without pinging every url, like a client-side ajax version has to.

    On top of that, you could filter the entire site since you have it in a string. for example, you could path certain thing for certain browsers, pass a dev query string that triggers changes no-one else can see, generates a site report spreadsheet using the meta info and counts from each page, creates a revisioning-friendly 'snapshot in time' of the entire site's content, and provides an opportunity to apply user-selected modifications like large fonts, low bandwidth, etc to all pages on-the-fly. these bonuses are on top of the now-available instant page loads and ability to browse the site offline.

    note that a much simpler version of the functionality semi-works in FF by simply replacing head.innerHTML, document.body.innerHTML, and calling pushState().
    Last edited by rnd me; 12-03-2012 at 05:52 PM.

  9. #9
    Join Date
    Jan 2011
    Location
    Munich, Germany
    Posts
    237
    Hi rnd_me,

    Thanks very much for you incredible feedback! It's amazing, to which lengths you've gone and how much R&D was involved.
    Very nice of you, to open up the code to the public. I suppose you're so busy with your other working life, that you don't have the time to forth-pursue it.

    In the meantime, I've integrated script handling, so that it works for this: http://www.oeko-fakt.de/produkte/ .
    This is much like Balupton's code, only that it executes script "deltas" - compared to the page loaded before.
    The exciting thing is that I've reverted the included libraries to their original state - with .ready() written in them and it works!
    That means, the solution is probably generically practible. (.ready() in those scripts does get fired, when appended to the content div...)

    When adopting Balupton's code 1:1, I noticed that scripts were being fired twice. Now, looking at Firebug, everything's cool - and run-time performance is good.
    (for current code, please see: http://4nf.org/history.js)

    Obviously, we've got slightly different interests. You are more for conventional JS implementations - I'm freshly in love with jQuery and think it would be really hard,
    to code the gear lower-level.

    I had a look at your code. You would like to cache the whole site. I don't know, whether that slows down the initial page load a bit?
    Then there are other challenges - what if the server-side changes - what is the rule when to update in time?
    Caching the whole site is way over my head and far beyond the scope of what my little Gist aims at.
    But thanks anyway for trusting me with the code... It's all your's, if you still like the idea, then go for it!

    (You've also implemented compressing and cleaning up half-functional HTML - unbelievable!)

    Here's what's on my ToDo list for the moment:

    - Support passing several div IDs to the plugin in jQuery style while, if possible maintaining chainability, as described in the jQuery authoring guidelines
    (in this context - making the inital "body div :first" load perform only once, along with the inclusion of scripts)

    - Update documentation of the Gist - any ideas are welcome!

    - Getting people to participate at GitHub - I have no idea how that works - just issued a "Pull Request" - nothing's happening?

    Anybody know how to publish your work properly at GitHub in case of a Gist?


    Thanks once more so much for your generous support and hope you aren't disappointed.
    (I want to keep things simple, the main difference to Balupton's code being the better jQuery encapsulation of the History API and the lean plugin interface)

    Sure you don't want to dive into jQuery? (there is a massive trend towards it)


    Kind regards

  10. #10
    Join Date
    Jan 2011
    Location
    Munich, Germany
    Posts
    237
    Hello all,

    I've completely overhauled the plugin code: http://4nf.org/history.js

    You can now call it this way:

    Code:
     $(document).ready(function(){
              $("#content, #nav").history({ 'div1' : 'body div:first' });
    });
    In the above example, first $('body div:first') would be ajaxified, then iteratively $('#content') and $('#nav').
    You can see it working on http://4nf.org/ and http://www.oeko-fakt.de/

    I have also done the following:

    - Updated the GIST: A jQuery encapsulation of the HTML5 History API

    - Introduced the default event 'statechangecomplete' to be triggered if given.

    - Added checking for the class '.no-ajaxy' for links that are not supposed to be ajaxified.

    - Added Google Analytics handling

    - ADDED SCRIPT HANDLING:

    Scripts are now compared with the previous page and deltas only are loaded!
    I think this is better than what Balupton was doing, which didn't work very well for me.

    --------------------------------------------------

    How do you think I can further improve the code: http://4nf.org/history.js

    Does anyone else feel like trying the plugin out?


    Thanks and kind regards
    Last edited by arvgta; 12-20-2012 at 08:35 AM.

  11. #11
    Join Date
    Jan 2011
    Location
    Munich, Germany
    Posts
    237
    Hello all,

    I have added some more documentation on:

    - https://gist.github.com/4017712
    - http://4nf.org/history-api/

    Please see also: https://forum.jquery.com/topic/new-plugin-history-api

    Do you think the documentation is comprehensive?

    Any other ideas?

    Best New Year's wishes and kind regards

  12. #12
    Join Date
    Jan 2011
    Location
    Munich, Germany
    Posts
    237
    (Google seems to love this thread, is why I'm posting after a long time, just stumbled across it - please excuse)

    Lot's has happened in the meantime, thanks very much rnd_me for your excellent feedback!

    Anyone interested in the topic, please check out: http://4nf.org/change-content-div/ for extensive documentation about what's become of this story!

    Any feedback is greatly appreciated, if you like, drop us a comment here:
    http://4nf.org/change-content-div/#comments


    Kind regards, Arvind.

  13. #13
    Join Date
    Jun 2013
    Posts
    1
    thanks for this plugin.

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center



Recent Articles