What is the advised method to make a chat window scrollable, using an iframe or a scrollable div? What are the pros&cons of the two techniques? Which would you opt for and why?
Thanks
You can create a script that will embed a chat into a third-party website creating both <div> or <iframe>
The main interesting differences
iframe
Code: All user events (clicks, key events, hovers etc) are handlable exclusively from your external chat app page. Without a complicated API the user will not be able to easily modify or target desired events to suit their needs (Why should they after all). The sensitive backend code and logic can stay hidden on your side.
Styling: Your chat app will look exactly like you defined it. With an extended API the user will only be able to select some predefined styles. (I personally hate that.) So more coding for you.
Uses Mostly used by free chat apps where they force the app to be just the way they want it to be, preventing custom styles and possibly the removal of the App logo, link to the from site, or some random ads. Also used if you want to provide the data storage on your side, or provide silent application updates.
Scroll and heights are unaware of the surrounding items which ends mostly having an API where the user chooses some predefined chat heights.
DIV
Code: All user events (clicks, key events, hovers etc) are easily accessible and modifiable to the programmer. You can still have a nice plugin / API that will simplify customizations to the user.
Styling: The DIVs being rendered inside the user page will inherit that page styles.
The good part it that the chat app will have a design that suits perfectly the page design.
The hard part is that in your CSS you'll have to probably prevent some chat sensitive styles to be overwritten by the host page styles. Be careful.
Uses: people are gonna love it. If you want users to keep your link or logo you can ask them to keep the copyright or the link. You cannot count that this will happen. If you sell your app, or you just don't care, than I find this use the proper one.
Scroll and heights of chat elements are aware of the surrounding document. My suggestion here is to create a fluid chat app using %. That way your app will fit inside every container, and if it's a fluid page... more love for you.
So even if I would personally choose the <div> one, it's totally up to your needs.
Regarding scrollability I've created a nice UI technique:
Create a variable-flag that will register if the scrollable area is hovered
after you ping the server for the new message, run a function that will scroll the area to bottom
if the scrollable area is hovered means that the user is reading old chats
on mouseleave = scroll automatically the chat to the bottom (last conversation)
See it in action here
HTML:
<div class="chat">
<div class="messages">
<div>Old message</div>
</div>
<textarea></textarea>
<button>Post</button>
</div>
BASIC CSS (more CSS in the demo link):
.chat{
position:relative;
margin:0 auto;
width:300px;
overflow:hidden;
}
.chat .messages{
width:100%;
height:300px;
overflow:hidden;
}
.chat .messages:hover{
overflow-y:scroll;
}
.chat .messages > div{
padding:15px;
border-bottom:1px dashed #999;
}
jQuery:
var $chat = $('.chat'),
$printer = $('.messages', $chat),
$textArea = $('textarea', $chat),
$postBtn = $('button', $chat),
printerH = $printer.innerHeight(),
preventNewScroll = false;
//// SCROLL BOTTOM
function scrollBottom(){
if(!preventNewScroll){ // if mouse is not over printer
$printer.stop().animate( {scrollTop: $printer[0].scrollHeight - printerH }, 600); // SET SCROLLER TO BOTTOM
}
}
scrollBottom(); // DO IMMEDIATELY
function postMessage(e){
// on Post click or 'enter' but allow new lines using shift+enter
if(e.type=='click' || (e.which==13 && !e.shiftKey)){
e.preventDefault();
var msg = $textArea.val(); // not empty / space
if($.trim(msg)){
$printer.append('<div>'+ msg.replace(/\n/g,'<br>') +'</div>');
$textArea[0].value=''; // CLEAR TEXTAREA
scrollBottom(); // DO ON POST
// HERE Use AJAX to post msg to PHP
}
}
}
//// PREVENT SCROLL TO BOTTOM WHILE READING OLD MESSAGES
$printer.hover(function( e ) {
preventNewScroll = e.type=='mouseenter' ? true : false ;
if(!preventNewScroll){ scrollBottom(); } // On mouseleave go to bottom
});
$postBtn.click(postMessage);
$textArea.keyup(postMessage);
//// TEST ONLY - SIMULATE NEW MESSAGES
var i = 0;
intv = setInterval(function(){
$printer.append("<div>Message ... "+ (++i) +"</div>");
scrollBottom(); // DO ON NEW MESSAGE (AJAX)
},2000);
I will myself always go for a div for a chat application, Why?
Here is basic benefit. You can handle the events on a div, that you cannot handle using an iframe. You can try it for yourself, try to handle click, mouseover events inside an iframe, you won't get anything.
$('div').click(function () {
alert('Div was clicked!');
}
While iframe won't let you access events on the child elements of it.
While div will provide each and every event to the parent or even the js to handle and do the coding as necessary. For iframe you need to handle the events inside the iframe, lets say the page from where the iframe was loaded, its events are inside the code that was used to create it.
$('iframe').click(function () {
// code..this will execute when click is on iframe, not for a child
}
But you cannot do something as
$('iframe html body div').click(function () {
/* techniques for iframes are different and harder as
* compared to ones used for div, to get a child event
*/
})
But the elements inside the div can be embedded for your webpage. And you can always change its child or parent elements. So chat app will be better, if you can handle all the element events.
<div>
Some text
</div>
jQuery
$('div').on('event', function () { // on an event..
// so on, adding more and more event handlers and blah blah
})
In a div, you can just update the content using ajax request, and then add it to the div and you can also use jQuery API to scroll it. No matter how much page size, you can use % or exact place where to scroll to. So divs are simpler.
$('div').load('chat_page.php'); // load a page in the div
Or just update it using,
$.ajax({ // create ajax request
url: 'chat_message', // url
success: function (resp) { // if OK
$('div').html(resp); // update the page
}
});
Iframes are generally used to let others use your functionality, such as embedding chat application in a third party site, where you don't need them to edit or reuse your code. So you give them an iframe and a link.
Scolling thing was not understood by me! :( Sorry about that, I think I am going to write vague answer for that, so I will let that part go but this is how you can scroll the element
$('div').scrollTo(10); // scroll 10px down..
(You asked for browser support in comments) However, jQuery is supported cross-browser and cross platform. And the remaining part is HTML which is supported everywhere!
http://jquery.com/browser-support/ Here is a link to know the browser support
I prefer to use div as you can easily manage everything about it and it is easier to refresh, using less data for download for the server. Just a personal opinion.
PROS or DIV include less data, insert anywhere any time, and ability to easily use data for other tasks if needed on the page.
Pros of IFRAME easier to setup and code and easier ability to make it stand alone.
Cons of Iframe and it is harder to access data within and requires more code to do so if needed and cons of div are getting all the css and code right and inplace for the div and its parents and its children for it to flow correctly and nicely.
Related
Point
The code I have here is from my "operating system" I'm trying to create inside a browser by putting iframes in AppWindows with PHP code as the backend or the (main program process).
Now in every GUI system you have the ability to move windows, stack one on top of each others and such, but I'm not able to do efficiently in HTML using jQuery & jQuery-UI.
I'm using draggable() and some tricks I've found on StackOverflow to be able to bring the div AppWindow on top.
The problem
The code for bringing the **AppWindow** on top works fine but the problem is the iframe inside that window gets reset, because what this code is doing is that it stacks the current div as the first div above all the others inside the parent container.
If you notice the AppWindow 1 iframe blinks when you click on that window, I don't want that.
Code (jQuery)
$(function() {
// Don't know what I'm doing with iframe here...
$('.AppWindow iframe').click(function(){
$(this).parent().child.parent().append(this);
});
$('.AppWindow').click(function(){
$(this).parent().append($(this));
});
$('.AppWindow').draggable({handle:".DragHandle"});
});
Conclusion
If there is a way of preventing this from happening feel free to write an answer below. If you have a better way such as "JavaScript OS UI Framework" or something like that you're even more free to write below.I want something like **os.js** or **windows93.net** type of thing. All I need is a working taskbar, working window and a way to easily embed a PHP page inside that window that will mimic the work of the application.
I don't think it's possible. Take a look at here.
But
why do you reorder windows by change their positions in the dom in the first place? You could simply work with z-index. A basic example where you just set an active class of the targeted frame.
$(function() {
$('.AppWindow').draggable({
handle:".DragHandle",
drag: function(event, ui){
updateActiveWindow(event.target);
}
});
$('.AppWindow').on('click', function(){
updateActiveWindow(this);
});
function updateActiveWindow(el) {
$('.AppWindow').removeClass('active');
$(el).addClass('active');
}
});
with following css changes
.AppWindow.ui-draggable-dragging,
.AppWindow.active {
z-index: 1;
}
Edit: optimized the js a bit so that the window turns active once you start dragging.
In web development it's quite popular idea to create the element with fixed position and transparent background color which covers the whole page until the user interacts somehow (by accepting consent or paying for the service). Then the element is removed and user can use the web page.
Here's the example:
However user can remove the element manually, using dev tools in the browser.
Is there any way to prevent it? Is it possible to disallow some particular element to be deleted?
You can't.
The browser belongs to the user and is completely under their control.
If you don't want to provide them with something before they accept terms, then don't send the something to the browser until they have.
As far as it seems to be impossible to prevent the user from removing an element it is possible to detect the element removal.
The MutationObserver API allows us to detect changes of a particular DOM element.
Here's example by Jakub Jankiewicz
var in_dom = document.body.contains(element);
var observer = new MutationObserver(function(mutations) {
if (document.body.contains(element)) {
if (!in_dom) {
console.log("element inserted");
}
in_dom = true;
} else if (in_dom) {
in_dom = false;
console.log("element removed");
}
});
observer.observe(document.body, {childList: true});
When the element is removed we can of course add it again or redirect to error page indicating that any manipulations of the page are illegal.
In particular the deletion of the element is easy with this React extension. If we use React then we can just wrap the element we want to prevent from being deleted in the component:
import { WatchForRemoval } from 'react-mutation-observer';
...
<WatchForRemoval onRemoval={console.log.bind(null, 'Child removal triggered.')}>
<div>
Removing this element will trigger callback
</div>
</WatchForRemoval>
This is not possible. You can make it harder for the user to get around it, but you can't prevent them from removing it from the page.
I've seen websites use a lot of different solutions for making it harder to get around, ranging from locking the scrolling of the page to fully removing the content behind the pop up, but ultimately you can't prevent the user from modifying the DOM.
You need to add control server side.
Your user can control the data they receive. Don't send the data if you don't want them to access data.
I am currently working on a django chat application which involves using ajax to load the list of chat messages and appending them to one of the divs in my template via jquery (e.g. chatmsg_div).
Since the chat app will be used by many users, I am required to do pagination for the chat messages which I have been successful in doing so. Now, only the last 20 chat messages in the chatroom will be loaded for the users to see (with the latest message being at the bottom of the div).
However, there is another requirement that I need to do which is to load the chat history (e.g. previous 20 messages that is in another page) upon scrolling to the top of the chatmsg_div.
My questions will be:
I did some research on google, but could not find any jquery function that allows me to trigger an ajax call upon reaching the top of a specific div. I am pretty new to jquery, so please pardon me even if the answer I am looking for is obvious.
After loading the previous 20 chat messages, I want the div to remain at the position I last scrolled to instead of going to the top of the div
So far, I have tried:
$('#chatmsg_div').scroll(function () { if ($(this).scrollTop() > 100) { debugger; }
});
Thanks in advance for anyone who can answer my questions.
For checking if you need to scroll when a new messages arrived and it's not visible because the user have scrolled to top, you can do:
var shouldScroll = (content.scrollTop + content.offsetHeight >= content.scrollHeight);
Where the content is your DOM container of messages
For detecting if the page is scrolled to the top most:
if (content.scrollTop == 0) {
// load message history here
}
Now, for implementing auto scroll for new messages and the current scroll is at the bottom of the page, you could do:
if (shouldScroll) {
content.scrollTop = content.scrollHeight;
}
This should answer all your questions provided that you have enough knowledge to do the other task. No need to use jQuery
I'm adding a chat feature to a couple of our websites. The chat will connect users with people at our help desk to help them use the websites. Our help desk folks want the chat window to appear like a tab on the side of the page and slide out, rather than popping up in a new window. However, I want to allow the user to navigate around the site without losing the chat.
To do this, I've been trying to move the entire page into an iframe once the chat starts (with the chat outside the iframe), so the user can navigate around the site within the iframe without losing the chat.
I used this answer to get started, and that works great visually. However, some of the javascript in the background breaks.
One of the sites is ASP.NET web forms. The other is MVC. I've been working with the web forms one first. Stuff like calling __doPostBack breaks once the page is moved into the iframe since the javascript context is left behind.
Once the user clicks on a link (a real link, not a __doPostBack) and the iframe refreshes, then everything works perfectly.
How I see it, I have a few options:
Copy all javascript variables from window.top into the iframe somehow. Hopefully without having to know all the variable names. I tried this.contentWindow.__doPostBack = window.top.__doPostBack, which works, but other variables are missing so it ultimately fails:
Somehow switch the iframe's context to look at the top window context, if that's even possible? Probably not.
Another thought was to not move the page into an iframe right away, but to wait until the page changes and then load the new page into a new iframe. But I'm not sure how to hook into that event and highjack it.
Something else?
These are sites for use by our employees only, so I only have to support IE11 and Chrome.
Update:
Thanks to LGSon for putting me on the track of using the target attribute (so I can use approach #3). Below is what I ended up doing. When I pop out the chat, I call loadNextPageInIframe(). I'm using jQuery here since we already use it on our site, but everything could be done without. I set the target on all links that don't already have a target pointing to another frame or _blank. I left _parent out, but I don't think we use it anyway.
I have a reference to my chat window div in a global variable called 'chatwindow'.
There still could be some cases where this doesn't work, such as if there is some javascript that sets window.location directly. If we have anything in our sites that does this, I'll have to add a way to handle it.
function loadNextPageInIframe() {
var frame = $("<iframe id=\"mainframe\" name=\"mainframe\" />").css({
position: "fixed",
top: 0,
left: 0,
width: "100%",
height: "100%",
border: "none",
display: "none"
}).appendTo("body");
$("form, a:not([target]), a[target=''], a[target='_top'], a[target='_self']").attr("target", "mainframe");
var firstload = true;
frame.load(function () {
//Runs every time a new page in the iframe loads
if (firstload) {
$(frame).show();
//Remove all elements from the top window except the iframe and chat window
$("body").children().not(frame).not(window.top.chatwindow).remove();
firstload = false;
}
//Make the browser URL and title reflect the iframe every time it loads a new page
if (this.contentWindow && this.contentWindow.location.href && window.top.location.hostname === this.contentWindow.location.hostname && window.top.location.href !== this.contentWindow.location.href) {
var title = this.contentDocument.title;
document.title = title;
if (window.top.history.replaceState) window.top.history.replaceState(null, title, this.contentWindow.location.href);
}
});
}
May I suggest you do the following
get all links
attach an event click handler to intercept when someone click a link
on click event, check if chat is in progress, and if, feed the iframe with the new link
var links = querySelectorAll("a");
for (var i = 0; i < links.length; i++) {
links[i].addEventListener('click', function(e) {
if (isChatInProgress()) {
e.preventDefault(); //stop the default action
document.getElementById("your_iframe_id").src = e.target.href;
// anything else here, like toggle tabs etc
}
});
}
Update
To handle forms I see 4 ways at the moment
1) Add an onsubmit handler to your forms
function formIsSubmitted(frm) {
if (isChatInProgress()) {
frm.target = "the iframe";
}
return true;
}
<form id="form1" runat="server" onsubmit="return formIsSubmitted(this)">
2) Add a click handler to your buttons
function btnClick(btn) {
if (isChatInProgress()) {
btn.form.target = "the iframe";
}
return true;
}
<asp:Button runat="server" ID="ButtonID" Text="ButtonText"
OnClick="Button_Click" OnClientClick="return btnClick(this);" />
3) When a chat start, you iterate through each form and alter its target attribute
function startChat() {
var forms = querySelectorAll("form");
for (var i = 0; i < forms.length; i++) {
forms[i].target = "the iframe";
});
}
4) Override the original postback event (Src: intercept-postback-event)
// get reference to original postback method before we override it
var __doPostBackOriginal = __doPostBack;
// override
__doPostBack = function (eventTarget, eventArgument) {
if (isChatInProgress()) {
theForm.target = "the iframe";
}
// call original postback
__doPostBackOriginal.call(this, eventTarget, eventArgument);
}
Update 2
The absolute best way to deal with this is of course to use AJAX to load both page and chat content, but that likely means a quite bigger work load if your sites aren't already use it.
If you don't want to do that, you can still use AJAX for chat and if a user were to navigate to a new page, the chat app recreate the ongoing chat window with all its content again.
I suggest instead of loading content to and from iframes - build the chat as an iframe and use a jQuery modal popup on the page for chat.
You can fix the jquery modal to a fixed location and page scrolling is enabled by default. You need to modify css accordingly to make the popup remains on the same location.
If you go down your current path - you will need to worry a lot about how content is moved to the iframe and it might be difficult to re-use the chat on different pages depending on the content. For example, imagine you playing a video on the page and the user clicks chat - if you load the content to the iframe - the user will lose the status on how far he has viewed, etc.
as per my opinion, adding the whole website as an 'I-Frame' is not a good design practice, and not a good solution for the problem. My suggestion would be:
Ensure that the 'Chat' application is loaded in all the pages, across your website
Whenever the 'Chat' is started, either establish the 'web-socket' connection or somehow, maintain the State on the Server
Have the configuration of the 'Chat' as 'Minimized', 'Open' etc and store them in your cookie or session storage
On every page load, call the 'Chat' application too. Read the Chat related configuration from sessionstorage or cookie and maintain it's state as 'Minimized' or 'Open' etc, including the X and Y position, if you want to make it as 'Floated'
Every time, either fetch the entire conversation from the server via Ajax or try to store and fetch from 'Local Storage' and do Ajax only for any Updates from the other party
Use CSS based 'Float' related properties to make it float and sit at some side.
This will ensure that your chat is available for the user and yet he can navigate all through the site.
The main goal is to keep non-refreshed the logotext <div class="small-7 medium-4 columns logo"> and the menu <nav class="pagedMenu" role="navigation">,without clipping on page refresh or while the content is loading from a page to another. Also, the menu state should be preserved from a page to another.
I've found here a possible solution that could solve the problem (you could use ajax to fetch the updated content and use jQuery to put the new content on the page and avoid the refresh entirely. Doing it that way, the existing data in the page would remain untouched. said #jfriend00)
So, I have tried to use an Ajax plugin (called AWS). In the AWS option page, I (suppose) that I've done the right thing pointing wrapper as Ajax container ID and also pagedMenu as Menu container class, Transition Effect Enabled, No ajax container IDs blank, no loader selected, having already a pulse loader implemented in the theme.
At this point, all I got it's a menu / side-menu (shiftnav) / pulse dot loader / content loading malfunction, generated perhaps by the wrong defined Ajax container id and/or menu container class(?) OR by a conflict with an existing JS / jQuery code, not so sure.
Also in Chrome console there is an error:
Uncaught SyntaxError: Unexpected token ;
(anonymous function) # ajaxify.js?ver=4.3.1:175
n.extend.each # jquery-2.1.4.min.js?ver=2.1.4:2
n.fn.n.each # jquery-2.1.4.min.js?ver=2.1.4:2
$.bind.$.ajax.success # ajaxify.js?ver=4.3.1:169
n.Callbacks.j # jquery-2.1.4.min.js?ver=2.1.4:2
n.Callbacks.k.fireWith # jquery-2.1.4.min.js?ver=2.1.4:2
x # jquery-2.1.4.min.js?ver=2.1.4:4
n.ajaxTransport.k.cors.a.crossDomain.send.b # jquery-2.1.4.min.js?ver=2.1.4:4
Everything is getting back to normal on page refresh but doesn't help at all, being useless.
I also have to mention that for the menu I've tried to keep the state using jQuery-Storage-API and storage=jQuery.sessionStorage; as you can see in mynewmenu.js file but that will not solve the non-refreshing elements problem.
The menu jsfiddle only, if this helps to have the whole picture, here thanks to #Diego Betto.
You can use this live link as example; there is a similar situation with the above described - Ajax implementation right(?) - and regarding the appearance, menu is kept non-refreshed from one page to another; if you browse Books, Works etc, menu sections you'll see; if there is a model that could be implemented here, I'll be glad to find it.
LE: meanwhile, I've tried another ajaxify solution made by #arvgta - special thanks - without success yet but as far as I've found from the Author, the defined elements should be div's with id's not classes. So, I'll try to find a way to modify somehow the code in order to have id instead on classes.
Also, I'll try to transform and implement in ajaxify.min.js file, the page-container element; jQuery('#page-container').ajaxify(); I'll come back with news.
LE2: I've tried to implement the solution using id's instead of classes but still, the pages are not loading correctly.
At this point we have ajax.min.js file updated with these lines:
(function($){
jQuery(document).ready(function(){
jQuery('#page-container').ajaxify({requestDelay:400,forms:false});
});
})(jQuery);
Also, I've modified the theme file to have id=page-container instead if class=page-container.
In these conditions, on menu click, the links are changed (like it should), menu/ logotext elements seems to working almost fine (sometimes get skippy changing position), but the content is not loading correctly in all cases; Same here, everything is getting back to normal on manual page refresh (f5), but doesn't help.
LE3: It looks like the conflict is (at least) between Revolution Slider plugin and Ajaxify.
errormessage="Revolution Slider Error: You have some jquery.js library include that comes after the revolution files js include." ;="" +=" This includes make eliminates the revolution slider libraries, and make it not work." "<="" span="">"
Site live link here. Any thoughts / alternative in this area? (not interested in using other different platforms, different WordPress themes, etc. just a workaround in this existing situation)
LE4: As far as I can see, there are many users that voted up the Jake Bown answer that could be indeed a solution; but I can't find the reason that didn't work correctly implemented into my theme (without errors) live link here The elements logotext / menu are still fading on refresh, are not kept non-refreshed. Any thoughts #Jake Bown / anyone?
LE final.
Buzinas delivered the closest answer for my needs, taking in consideration my site environment (plugins installed, etc).
From what you said I think I might have found the solution you're looking for - you want to load content dynamically whilst keeping the logo and navigation untouched? If so, this might be what you're looking for.
In the example, the pages are loaded in from a div within the page but could be used to load another URL or file:
$('.viewport ul li a').on('click', function(e) {
e.preventDefault();
var link = this.hash.substring(1, this.hash.length);
if($('.'+link).length) {
$('.viewport span.body').html($('.'+link).html());
}
});
TL;DR
I've created a plunker for you, take a look, and play with it as long as you can. You'll learn a lot from it!
I think you're trying too many things here, but didn't try the simplest:
The main goal is to keep non-refreshed the logotext and the menu ,without clipping on page refresh or while the content is loading from a page to another. Also the menu state should be preserved from a page to another.
If you want to do that, there are a few steps:
Create a 'master' page, that we're going to call index.html from now on.
So, our index must have the static part of our page, e.g menu, logo, footer etc.
Then, our 'subpages' must be cut down (no html, head, body, script, style tags, only the content that should be showed into our master page).
That done, now we must change our links to use AJAX instead of doing full refresh:
/* we add a 'click' event handler to our menu */
document.getElementById('menu-menu-2').addEventListener('click', function(e) {
var el = e.target;
/* then, we see if the element that was clicked is a anchor */
if (el.tagName === 'A') {
/* we prevent the default functionality of the anchor (i.e redirect to the page) */
e.preventDefault();
/* we show our spinner, so the user can see that something is loading */
spinner.classList.remove('hidden');
/* and we call our AJAX function, passing a function as the callback */
ajax(el.href, function(xhr) {
/* we get our main div, and we replace its HTML to the response that came
from the AJAX request */
document.getElementById('main').innerHTML = xhr.responseText;
/* since the request was finished, we hide our spinner again */
spinner.classList.add('hidden');
});
}
});
Ok, now our pages are already working via AJAX, and not reloading our static content.
But now, we see that we have some issues. For example, if someone tries to open one of our pages directly via URL, he'll see unstyled page, without the menu/logo etc. So, what should we do?
We have a few more steps now:
Simulate that our links are effectively transfering between pages using the History API:
/* inside our ajax callback, we save the fake-redirect we made into the pushState */
ajax(el.href, function(xhr) {
document.getElementById('main').innerHTML = xhr.responseText;
/* save the new html, so when the user uses the back button, we can load it again */
history.pushState({
html: main.innerHTML,
title: el.textContent + '| neuegrid'
}, '', el.href);
/* (...) */
});
/* and outside it, we add a 'popstate' event handler */
window.addEventListener('popstate', function(e) {
/* so, if we've saved the state before, we can restore it now */
if (e.state) {
document.getElementById('main').innerHTML = e.state.html;
document.title = e.state.title;
}
});
And we need that when the user enters directly to another page, e.g about-us, we redirect him to the index.html, and then load the about-us page from there.
So we create a redirect.js file, and we reference it in all of our
subpages:
/* save the page that the user tried to load into the sessionStorage */
sessionStorage.setItem('page', location.pathname);
/* and them, we redirect him to our main page */
location.replace('/');
And then, in our index.html page, we see if there is any page in the sessionStorage, and we load it, if there is, otherwise we load our home page.
var page = sessionStorage.getItem('page') || 'home';
/* we look into the menu items, and find which has an href attribute
ending with the page's URL we wanna load */
document.querySelector('#menu-menu-2 > li > a[href$="' + page + '"').click();
And that's it, we're done now. Take a look at the plunker I've been making to you.
And play with it as long as you can, so you'll learn a lot from it.
I hope I could help you! :)
Note: Just for reference, this is our ajax function:
function ajax(url, callback, method, params) {
if (!method) method = 'GET';
var xhr = new XMLHttpRequest();
xhr.open(method, url);
if (callback) xhr.addEventListener('load', function() {
callback.call(this, xhr);
});
if (params) {
params = Object.keys(params).map(function(key) {
return encodeURIComponent(key) + '=' + encodeURIComponent(params[key]);
}).join('&');
xhr.send(params);
} else {
xhr.send();
}
}
GOING AJAXED WITH WORDPRESS
demo: http://so.devilmaycode.it/how-to-keep-elements-non-refreshed/
follow these simple steps (let's take as example theme "twentyfifteen" on the WP templates folder):
edit single.php, page.php, index.php and all other pages having get_header() and get_footer() functions and replace it respectively with below code:
NOTE: this is important because if someone (ex: search-engine) reach your pages directly from the link, it is still fully available and 100% working. (useful for SEO)
<?php
//get_header()
if(!isset($_REQUEST['ajax'])){
get_header();
}
?>
<!-- other code --->
<?php
//get_footer()
if(!isset($_REQUEST['ajax'])){
get_footer();
}
?>
open the header.php add the below code inside the <head> section at the very end
<script>
!(function($) {
$(function() {
$('.menu-item a, .widget-area a, .page_item a').on('click', function(e) {
e.preventDefault();
var href = this.href;
var query = href ? (href + (!/\?/g.test(href) ? '?' : '&') + 'ajax=1') : window.location;
/* IMPLEMENT SOME LOGIG HERE BEFORE PAGE LOAD */
/* ex: kill instance of running plugins */
$('#content').hide().empty().load(query, function() {
/* IMPLEMENT SOME LOGIG HERE AFTER PAGE IS LOADED */
/* ex: refresh or run a new plugin instance for this page */
jQuery(this).show();
});
});
});
})(jQuery);
</script>
in the header.php file put the code below at the end of the file, 90% of times you need it under the navigation. In this case we already have this on the "twentyfifteen" theme.
NB: most probably you have the opening tag <div id="content" class="site-content"> inside the header.php file and the closing tag </div> on the footer.php file, this doesn't matter, you can leave it as is.
<div id="content"></div>
NOTE: consider this a proof of concept; it may work as is, but you still need to tailor it to suit your needs; you may need to:
Add a menu (in case it is not already set) by going under Appeareace > Menus > [check Primary Menu] > Save Menu in order to activate the menu. it's tested and working.
You may want to add some other class to the jQuery function like .widget-area a in order to ajax also widget links.
if you are using 3d party plugins you may need to ensure that all dependencies of each plugin are loaded also on the main page from where you want everything is displayed without refreshing content.
you may need to check and kill those 3d party plugin before a new page load and run or refresh plugin needed in the loaded page.