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.
Related
I'm working on my schools webpage, and i'm trying to select all header elements inside a div with a class called "text" using the querySelector(String) function - and then changing the headers background, border, and text colour, but the following code doesn't seem to work
var test = "content.html #test"
$(document).ready(function()
{
$.ajax(
{
success : function(data)
{
$("#content").load(test); //this works - loads <div id="test"> and all elements within it from content.html
document.querySelector(".content").style.backgroundColor = "#CCFFCC"; //this works - exists inside main html file ( $(document) )
document.querySelector(".text h1").style.backgroundColor = "#CCFFCC"; //this doesn't work - still loading default colour from css
document.querySelector(".text h1").style.color = "#003300"; //this doesn't work - still loading default colour from css
//Appropriate close tags follow...
Would you guys know what i'm doing wrong? Am I referencing my elements in the wrong way? or does it have something to do with the fact that i'm trying to dynamically load this content from a separate file? Or something else entirely?
As Klaster_1 intimated, you need to utilize load's callback functionality.
$('#content').load(test, function() {
document.querySelector(".content").style.backgroundColor = "#CCFFCC";
document.querySelector(".text h1").style.backgroundColor = "#CCFFCC";
document.querySelector(".text h1").style.color = "#003300";
});
What Klaster_1 means when he says it's an "async" operation is that it runs out of sync of the rendering of the DOM. In other words, that code styling the content will be run before the browser's run loop has a chance to actually put the content on the page.
I am using CSS-Tricks dynamic page script found here.
http://css-tricks.com/dynamic-page-replacing-content/
$(function() {
var newHash = "",
$mainContent = $("#main-content"),
$pageWrap = $("#page-wrap"),
baseHeight = 0,
$el;
$pageWrap.height($pageWrap.height());
baseHeight = $pageWrap.height() - $mainContent.height();
$("nav").delegate("a", "click", function() {
window.location.hash = $(this).attr("href");
return false;
});
$(window).bind('hashchange', function(){
newHash = window.location.hash.substring(1);
if (newHash) {
$mainContent
.find("#guts")
.fadeOut(200, function() {
$mainContent.hide().load(newHash + " #guts", function() {
$mainContent.fadeIn(200, function() {
/*
$pageWrap.animate({
height: baseHeight + $mainContent.height() + "px"
});
*/
});
$("nav a").removeClass("current");
$("nav a[href="+newHash+"]").addClass("current");
});
});
};
});
$(window).trigger('hashchange');
});
Body
<body onload="onLoad()">
I am using a number generating script (below) on one of my pages, but I am having trouble getting it to only show on one, single page. When placed in the head of the document or my includes/scripts.php that is loaded on every page, it shows on every page. When only included on the page I want, it does not work.
<script>
function counter() {
var num = 0;
for (num = 0; num < 500; num++) {
document.write(num + ' ');
}
}
counter();
</script>
I have tried a few different things but can't seem to get it to only appear on a single page. Is there any way around this without ditching the CSS-Tricks Dynamic Page?
What if you insert your code into dynamicpage.js like this?
$(window).bind('hashchange', function(){
newHash = window.location.hash.substring(1);
if(newHash === 'somePage') { // the page you want to implement the effect
// your code
}
/*
....
*/
});
You might try adding a class to your <body> tag (or other near-to-top level wrapper if you're just dynamically loading to the HTML attribute of your body tag in the first place) that lets the script distinguish between pages that ought to use the function and those that don't, something like:
$(document).ready( function() {
$(`body.usesCounter`).on(eventToBeCounted, counterFuncAsCallback);
}
But the fact that it's not working when only loaded on a single page does suggest you've got something else going on. Can you give us the header for the single page, the script block (and where it is on the page), and some sense of how/when it's called?
Are you loading the single page dynamically? If you are, the script tags won't be accessible unless you reload the DOM somehow or else do some funky binding via jQuery's $.on() or something similar that listens for changes to the DOM.
UPDATE
Looking at the tutorial you are trying to emulate, the general problem you're facing is that the JS on that page you're loading isn't going to be registered with the DOM. I've had to write code that can read dynamically lodaded JS like this, and if you want to do it both effectively and securely, it's quite a lot of effort. The point of JS-based page loading is to be fetching "view-like" content; assets, html, etc.. In a single-page environment, any required logic should—generally—exist on that page.
I highly recommend you include the code in your initial page, and then conditionally call it when the appropriate page arrives. There are lots and lots of ways to do that, basically find some distinguishing feature of the page(s) where your counter should be run, and, after having loaded the page, look for said features and, if found, allow your code to run. You might have something as simple as a variable, isCounterPage set, by default, to false. Then, after a dynamic page load occurs, if the inspection fires and this var remains false, don't execute code associated with the counter. Otherwise, let it do its thing.
I am trying to fire a script when the contents of a div are altered, specifically when a div receives the next set of results from a js loaded paginator.
I have this:
<script script type="text/javascript" language="javascript">
document.addEventListener("DOMCharacterDataModified", ssdOnloadEvents, false);
function ssdOnloadEvents (evt) {
var jsInitChecktimer = setInterval (checkForJS_Finish, 111);
function checkForJS_Finish () {
if ( document.querySelector ("#tester")
) {
clearInterval (jsInitChecktimer);
//do the actual work
var reqs = document.getElementById('requests');
var reqVal = reqs.get('value');
var buttons = $$('.clicker');
Array.each(buttons, function(va, index){
alert(va.get('value'));
});
}
}
}
</script>
This works well when the doc loads (as the results take a few seconds to arrive) but I need to narrow this down to the actual div contents, so other changes on the page do not fire the events.
I have tried:
var textNode = document.getElementById("sitepage_content_content");
textNode.addEventListener("DOMCharacterDataModified", function(evt) {
alert("Text changed");
}, false);
But the above does not return anything.
Can what I am trying to do be done in this way? If yes where am I going wrong?
Using Social Engine (Zend) framework with MooTools.
I did this in the end with a little cheat :-(
There is a google map loading on the page that sets markers to match the location of the results. So I added my events to the end this code namely: function setMarker() {}.
I will not mark this as the correct answer as it is not really an answer to my question, but rather a solution to my problem, which is localised to the Social engine framework.
I will add a Social engine tag to my original question in the hope it may help someone else in the future.
Thanks guys.
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;
};
I have Drag/Drop functionality in my page embedded using YAHOO.js which is initalized at load of the page. When 'alert' is put in the init function, the Drag/Drop is working otherwise
it is not. Using Firebug I had debugged the code and seen when init function is called but not looping through the function when no alert is put.
This function should work when ALT key is pressed. I am using velocity template engine over JavaScript.
Sample code:
<script type="text/javascript" language="JavaScript">
var myLogger;
var dd1, ddTrashCan; // draggable div objs
#if ($displayOptions.isDoDragDropJavaScript())
YAHOO.util.Event.addListener(window, "load", DD_TestInit);
#end
function display(data) {
var output = "<div>" + data.text + "</div>";
element.innerHTML=output;
}
function DD_TestInit() {
#if ($showLoggerDiv)
initLogger();
#end
//display("date");
initDragObjects();
}
function logMsg(strMsg) {
if (myLogger)
myLogger.debug(strMsg);
}
function initDragObjects() {
//alert('---');
if (dd1) dd1.unreg();
if (ddTrashCan) ddTrashCan.unreg();
YAHOO.util.DDM.mode = YAHOO.util.DDM.POINT;
YAHOO.util.DDM.clickTimeThresh = 10;
## init constant drag objects, draggable div and droppable trash, resp.
dd1 = new lineSched_Draggable("dragDiv1");
ddTrashCan = new lineSched_Droppable("TrashCan");
}
What I had found is whenever I put an alert or call any window.open() this works fine.
Any clue whats happening here.
There is timer event which is delaying the process.My feeling is that this is a timing issue. The page is not fully in place when on load. The alert slows the process down, essentially the page is in place by the time the user clicks Ok on the alert. Clearly, we can’t deploy the app with an alert. But, we can look into different places to put the initialization. We can try to place it the same place I added the timing, when the page receives the last table. The page should be fully formed at this point and the function should work properly.