I have created a webpage that uses jQuery to show and hide elements. The obvious problem now arose; the back and forward browser buttons don't work anymore as everything is loaded within a single location.
I know the answer lies within jQuery History but after busting my head for several hours on their website and examples given here on stackoverflow, I still cant manage to:
A) create a history entry (I think i got this covered but not 100% sure)
B) animate the page transition with my own function (displayed beneath)
This is the website: www.grommit.nl
There are 4 sub-pages that require a history entry when called upon.
This code shows the transition of the "wordpress page". The other pages work in a similiar way. (so far I have only managed to generalize the last part of the pageload with the "LoadPageContent" function, the bit before that is different with every page)
var LoadPageContent = function() {
$(".sceneBody").slideDown(function() {
$(".aftertitle").css('width', '4em');
$(".mediacontainer").fadeTo('0.3s', 1,)
});
$("#goWordpress").click(function () {
$("#homeScene").fadeOut(function () {
$("#wordpressMessage").fadeIn(function() {
$(this).delay(300).slideUp(function() {
$("#wordpressPage, #grommitFixed").slideDown(function() {
LoadPageContent();
});
});
});
});
});
this is the function that is currently working as a previous button within the DOM. I would like this function to execute when the previous button is clicked.
var goBack = function() {
$(".aftertitle").css('width', '0em')
$(".mediacontainer").fadeTo('0.3s', 0, function() {
$(".scenebody, #grommitFixed").slideUp(function() {
$("*[id*=Page]:visible").each(function() {
$(this).slideUp(function() {
$("#homeScene").fadeIn();
});
});
});
});
};
In html5 you have something called pushstate, that you can use to tell the browser what to go back to. Check out:
html pushstate
Related
I have some custom JavaScript on my SquareSpace site that manipulates Product titles beyond what you can do with SquareSpace's default style editor. It works when initially loading the page (https://www.manilva.co/catalogue-accessories/) but if you click on any of the categories on the left, the styling resets to the default.
I'm assuming the JavaScript is being overwritten by the SquareSpace style, but I can't figure out why. Perhaps I'm calling the function in the wrong place?
Any suggestions would be helpful.
Thanks!
Current code:
document.querySelectorAll(".ProductList-filter-list-item-link".forEach(i=>i.addEventListener("click", function()
{
var prodList = document.querySelectorAll("h1.ProductList-title");
for (i = 0, len = prodList.length; i < len; i++)
{
var text = prodList[i].innerText;
var index = text.indexOf('-');
var lower = text.substring(0, index);
var higher = text.substring(index + 2);
prodList[i].innerHTML = lower.bold() + "<br>" + higher;
});
The source of your problem is that your template has AJAX loading enabled. There are currently a couple generally-accepted ways to deal with this as a Squarespace developer:
Disable AJAX loading
Write your javascript functions in a
manner that will run on initial site load and whenever an "AJAX load" takes place.
Option 1 - Disable AJAX:
In the Home Menu, click Design, and then click Site Styles.
Scroll down to Site: Loading.
Uncheck Enable Ajax Loading.
Option 2 - Account for AJAX in Your JS
There are a number of ways that developers approach this, including the following, added via sitewide code injection:
<script>
window.Squarespace.onInitialize(Y, function() {
// do stuff
});
</script>
or
<script>
(function() {
// Establish a function that does stuff.
var myFunction = function() {
// Do stuff here.
};
// Initialize the fn on site load.
myFunction();
// myFunction2(); , etc...
// Reinit. the fn on each new AJAX-loaded page.
window.addEventListener("mercury:load", myFunction);
})();
</script>
or
<script>
(function() {
// Establish a function that does stuff.
var myFunction = function() {
// Do stuff here.
};
// Initialize the fn on site load.
myFunction();
// Reinit. the fn on each new AJAX-loaded page.
new MutationObserver(function() {
myFunction();
// myFunction2(); , etc...
}).observe(document.body, {attributes:true, attributeFilter:["id"]});
})();
</script>
Each of those works for most of the latest (at time of writing) templates most of the time. Each of those have their advantages and disadvantages, and contexts where they do not work as one might expect (for example, on the /cart/ page or other "system" pages). By adding your code within the context of one of the methods above, and ensuring that the code is of course working in the desired contexts and without its own bugs/issues, you will have your code run on initial site load and on each AJAX page load (with some exceptions, depending on the method you use).
Your problem is the page does not reload when clicking a button on the left, just some elements are removed, added and replaced. The changed elements will not be restyled. You will need to re-run your JavaScript after one of those buttons is clicked. Perhaps something like this:
document.querySelectorAll(
".ProductList-filter-list-item"
).forEach(
i=>i.addEventListener(
"click", ()=>console.log("hello")
)
)
where you replace console.log("hello") with whatever resets your formatting.
I'm using the Win8 Grid View Template to display infos from a news site. In the lower menu bar i have implemented a function wich shuts off the titles, so that only the pictures are still visible.
This function is in a "global.js" file which is included in the "default.html" so it's available everywhere and it looks like this:
//function to turn titles off and on
function titleToggle() {
var titles = document.getElementsByClassName("item-overlay");
for (var i = 0; i < titles.length; i++) {
if (Global.titlesAreOn) {
titles[i].style.display = "none";
}
else {
titles[i].style.display = "";
}
}
Global.titlesAreOn = !Global.titlesAreOn;
};
So when i call this function from the menu bar it works for the first items, but when i scroll the end of the groupedItems view (hubview) the titles are still there. When i then scroll back to the beginning the titles are there again too.
I'm also calling the titleToggle function from the ready() function of the "groupedItems.js" to check whether or not to display the titles depending on a global variable. When i do that (whenever i come back to the hubpage) it works all the way, just as expected.
ui.Pages.define("/pages/groupedItems/groupedItems.html", {
navigateToGroup: function (key) {
nav.navigate("/pages/groupDetail/groupDetail.html", { groupKey: key });
},
ready: function (element, options) {
appbar.winControl.disabled = false;
appbar.winControl.hideCommands(["fontSizeBt"]);
appbar.winControl.showCommands(["titleToggle"]);
if (Global.titlesAreOn == false) {
Global.titlesAreOn = true;
Global.titleToggle();
}
I made a short video to show the problem, because its kinda hard to explain --> http://youtu.be/h4FpQf1fRBY I hope you get the idea?
Why does it work when i call it from the ready() function?
Does anyone have an idea? Is it some kind of automatic item caching in order to have better performance? And how could this be solved?
Greets and thanks!
First, here is why this might be happening - WinJS is using single page navigation for the app experience. This means that when you navigate to a new page, actually you don't. Instead the content is removed from the page and the new content is loaded in the same page. It is possible that at the moment you press the button not all elements have been loaded in the DOM and therefore they cannot be manipulated by your function. This is why when you call it from the ready() function it works - all contents are loaded in the DOM. It is generally better to do things in the ready() function.
About the behavior when you slide back left and the items are again reloaded with titles - for some reason the listView items are reloading. Maybe you are using live data from the news site and they are refreshing with the listView control's template again. I cannot know, but it doesn't matter. Hiding the elements is not the best approach I think. It is better to have two templates - one with a title element and one without. The button click handler should get the listView controls(they have to be loaded) and change their templates.
ready: function (element, options) {
var button = document.getElementById('btn');
button.addEventListener("click", btnClickHandler);
}
And the handler:
function btnClickHandler(e) {
var listView = document.getElementById("listView").winControl;
var template2 = document.getElementById("template2");
listView.itemTemplate = template2;
};
UPDATE:
I was able to get my scroller working as desired but I feel like I have hacked around the actual issue and would love it if anyone has a more solid answer, I've updated and noted in the snippets below the new jQuery I'm using.
I'm using iScroll-4 (http://cubiq.org/iscroll-4) for an iPad/Android web app, everything's working perfectly with the swipes and scrolling but I have a table of contents at the beginning of the app that allows users to jump to specific areas of the scroller --
I'm using the iScroll function scrollToElement(element, duration) in order to jump to the different areas. Also using scrollToPage(page, duration) to allow the user to manually navigate forward and backward one page at a time.
While watching the console logs the currPageX variable updates when I navigate with the scrollToPage function and when I swipe, but when using the scrollToElement the currPageX variable does not update.
Therefore if I jump to an element and then navigate forward with scrollToPage('next', 0) it will go backwards and navigate me to the next page after the table of contents.
I have tried using the scroll.refresh() function after scrollToElement, before, putting the function inside a timeout, etc. and I can't figure out why the currPageX is not updating.
Here's a snippet of the jQuery code that I'm using the two different functions:
// TO NAVIGATE FORWARD AND BACKWARDS
$('span.control').on('click', function() {
var slideDir = $(this).attr('data-dir');
if (slideDir == 'prev') {
var tehPg = tehScroll.currPageX-1;
} else if (slideDir == 'next') {
var tehPg = tehScroll.currPageX+1;
}
tehScroll.scrollToPage(tehPg, 0);
return false;
});
// TO JUMP FROM CONTENTS
$('li[data-page="toc"] span').on('click', function() {
var toPage = $(this).attr('data-page');
tehScroll.scrollToElement('li[data-page="'+toPage+'"]', 800);
// ADDED THE FOLLOWING LINE TO MANUALLY SET currPageX after scrolling!
tehScroll.currPageX = $('#slides li[data-page="'+toPage+'"]').index();
return false;
});
Did you consider using jquery-mobile-iscrollview widget plug-in? - there is a function scrollToPage(pageX, pageY, time), works well for me...
best
M
I am pretty new to Javascript so please bear with me.
$('#bioContent').css('display','none');
$('#skillsContent').css('display','none');
$('#credsTab').css('background-color','#fff');
$('#credsTab a').css('color','#19d700');
$('#bioTab').css('background-color','#ccc');
$('#bioTab a').css('color','#444');
$('#skillsTab').css('background-color','#ccc');
$('#skillsTab a').css('color','#444');
$('#credsTab').click(function(){
$('#credsContent').css('display','block');
$('#bioContent').css('display','none');
$('#skillsContent').css('display','none');
$('#credsTab').css('background-color','#fff');
$('#credsTab a').css('color','#19d700');
$('#bioTab').css('background-color','#ccc');
$('#bioTab a').css('color','#444');
$('#skillsTab').css('background-color','#ccc');
$('#skillsTab a').css('color','#444');
})
$('#bioTab').click(function(){
$('#bioContent').css('display','block');
$('#credsContent').css('display','none');
$('#skillsContent').css('display','none');
$('#bioTab').css('background-color','#fff');
$('#bioTab a').css('color','#19d700');
$('#credsTab').css('background-color','#ccc');
$('#credsTab a').css('color','#444');
$('#skillsTab').css('background-color','#ccc');
$('#skillsTab a').css('color','#444');
})
$('#skillsTab').click(function(){
$('#skillsContent').css('display','block');
$('#bioContent').css('display','none');
$('#credsContent').css('display','none');
$('#skillsTab').css('background-color','#fff');
$('#skillsTab a').css('color','#19d700');
$('#bioTab').css('background-color','#ccc');
$('#bioTab a').css('color','#444');
$('#credsTab').css('background-color','#ccc');
$('#credsTab a').css('color','#444');
})
That's my javascript implementation of tabs. Basically on click, divs hide away and others appear.
My problem with this is that on the skillsTab, there's an add skills method, and when I click on that, it refreshes the page, and when it does, it brings me back to the credsTab, the default when the page is loaded.
I was wondering if that's a way so that when it refreshes, it will stay on the skillsTab.
Keep state around, which can be done via fragment URLs or HTML5 history.
e.g., make opening up the skills tab change the fragment to #skills, which will remain across a refresh. Then check window.location.hash in your onLoad to determine what initial state your page should be in.
function switchToTab(tabName) {
// DOM/CSS manipulation etc. here
}
var tabs = ['bio', 'skills', 'creds'];
var initialTab = 'bio';
for (var i = 0; i < tabs.length; i++) {
(function(tabName) {
document.getElementById(tabName + 'Tab').addEventListener('click', function() {
switchToTab(tabName);
location.hash = '#' + tabName;
}, false);
})(tabs[i]);
}
window.addEventListener('load', function() {
if (location.hash[0] == '#')
switchToTab(location.hash.substr(1));
}, false);
window.addEventListener('hashchange', function() {
if (location.hash[0] == '#')
switchToTab(location.hash.substr(1));
else
switchToTab(initialTab);
}, false);
Untested, and there's plenty of JS libraries out there that abstract this away for you.
An initial suggestion. give all your tabs the same class, maybe class='toggleableTab' then you can use
$('.togglableTab').live('click',function(){
$('.togglableTab').not(this).hide();
$(this).show();
});
as for the page refresh. Look into using AJAX to "add" your skills live on the page without a full page refresh.
There are several tabbed solutions already in place that you could make use of - for example, http://jqueryui.com/demos/tabs/. JQuery UI is a great way to have a lot of this work done for you.
If you want to do it yourself, I would also suggest a solution using classes, but slightly different than other suggestions. Instead, have two classes, "activeTab" and "tabbable". In your css, define "activeTab" as visible, and "tabbable" as hidden. Give each tab an ID and the class of "tabbable". Have a hidden field in your form called "activeTabId". Make sure that this gets passed back from the server side when you load the page, including setting it to the default tab when you first load the page. You could then run the following code on page load to make it all play well together:
$(".tabbable").click(new function(){
$(".tabbable").removeClass("activeTab");
$(this).addClass("activeTab");
$("#activeTabId").val($(this).attr("id"));
});
$("#" + $("#activeTabId").val()).addClass("activeTab");
I am currently using jQuery-Smooth-Scroll to smoothly scroll up and down to various anchor positions on one of my pages (Page 1). However, what I would also like to be able to do is, from another page (Page 2), link to Page1 (appending #bookmark to the url) and have jQuery-Smooth-Scroll pick up on the fact I am calling the page with a #bookmark and have it smoothly scroll down to the relevant position once the page has completed loading. I don't know if this is a possibility or not?
This is the version of Smooth-Scroll that I'm using:
https://github.com/kswedberg/jquery-smooth-scroll
I'm still relatively new to jQuery so I may be overlooking something obvious.
Ajma's answer should be sufficient, but for completeness:
alert(location.hash)
Edit: a more complete example:
// on document.ready {
if (location.hash != '') {
var a = $("a[name=" + location.hash.substring(1) + "]");
// note that according to w3c specs, the url hash can also refer to the id
// of an element. if so, the above statement becomes
// var a = $(location.hash);
if (a.length) {
$('html,body').animate({
scrollTop: $(a).offset().top
}, 'slow');
}
}
// }
It's possible, you want to put a call into the smooth scroll function when the page is finished loading. in jQuery, it's using $(document).ready(function () { your code } );
You'll need to put something in to parse your url to extract the #bookmark and then call the smooth scroll.