I'll try to explain my problem with few words.
I have an HTML with various iframes. In one iframe there is a Table of Contents (TOC) and in an other the content of the corresponding element highlighted in the TOC. Since there are various TOCs, it might happen that by clicking on a link, we'll be taken to a topic which belongs to another TOC, and therefore I want the TOC frame to be reloaded with the proper TOC. To do so, since each topic has a unique id within the TOC, I perform a search of the id of the topic loaded in the main frame accross all the TOCs and when I find the wanted TOC, I load it in the TOC frame.
The code I've written so far is the seguent:
/*function called on load of each topic - it gets the topic unique id as parameter*/
function highlight(id) {
/*the names of the HTML files containing the different tocs*/
var tocs = ["toc.htm", "toc_documentazione.htm", "toc_flussiesteri.htm", "toc_garante.htm", "toc_legittimita.htm", "toc_normativa.htm", "toc_settori.htm", "toc_sicurezza.htm", "toc_sistemadp.htm", "toc_vistaarticolato.htm"]
var i = 0;
/*search within the different TOCs until you find a correspondence or there are no more TOCs*/
while (!changeTOC(tocs[i], "a" + id) && i < tocs.length) {
i = i + 1;
}
/*this line is probably wrong but the idea is to load the found TOC in the appropriate frame*/
$(content).load(tocs[i - 1] + " #content");
}
/*function using ajax to search the id into the HTML file passed as parameter (newToc) returning the search outcome*/
function changeTOC(newToc, id) {
var found = false;
$.get(newToc, "html").done(
function(temp_toc) {
/*if the HTML contains the id we search for we return true*/
if (temp_toc.indexOf(id) != -1)
found = true;
});
/*else we return false*/
return found;
}
The problem I have is with the while cycle I use to search through the various TOC files. I did some debugging and, regardless from the fact the TOC containing the id I'm searching for is at the first position, the while extecutes 10 cycles and only at the very last it tells me that it has found the matching TOC, which is indeed the first one in the list.
Hope I've been able to make myself clear.
Thanks for your help
I finally managed to get this done by using the ajax call with syncronus set to true. I'm not posting here all the code cause it would be confusing, but below is what I changed compared to the code written above and now everything works just fine. Maybe it's not optimal in terms of performance but I don't have this concern, so I'm happy with it :)
Hope this can help others.
/*function called on load of each topic - it gets the topic unique id as parameter*/
function highlight(id) {
var tmpVal = sessionStorage.getItem('key');
//we check if there is another element in the TOC currently highlighted in bold, if so we remove the highlight
if(tmpVal) {
var tmpEle=parent.window.frames[0].document.getElementById('a'+tmpVal);
if (tmpEle) {
tmpEle.className='';
}
}
//loop through all TOCs to find the one containing the selected topic
var tocs = ["toc.htm","toc_documentazione.htm","toc_flussiesteri.htm","toc_garante.htm","toc_legittimita.htm","toc_normativa.htm","toc_settori.htm","toc_sicurezza.htm","toc_sistemadp.htm","toc_vistaarticolato.htm"];
var i=0;
while (!changeTOC(tocs[i],"a"+id)&&i<tocs.length){
i=i+1;
}
//get currently loaded TOC
var currentToc=$("#toc_iframe",parent.document).attr("src");
var indexCurrentTOC=tocs.indexOf(currentToc);
//we check if the matching TOC is the current one, if so we don't change anything
if(!changeTOC(tocs[indexCurrentTOC],"a"+id)){
$("#toc_iframe",parent.document).attr("src",tocs[i]);
}
var myElt=parent.window.frames[0].document.getElementById('a'+id);
//highlight current element in the TOC
myElt.focus();
myElt.className+=' active';
scrollTo(myElt.offsetLeft-48, myElt.offsetTop-(parent.document.body.clientHeight/3));
sessionStorage.setItem("key", id);
}
//searches for the element with given id into the toc file newToc
function changeTOC(newToc,id){
var found = false;
$.ajax({
url: newToc,
async: false,
context: document.body
}).done(function(temp_toc) {
if(temp_toc.indexOf(id)!=-1){
found = true;
}
});
return found;
}
Related
I have a home.html and faq.html.
The faq page has many questions and their answers listed consecutively down the page. I want the answers hidden until a question is clicked that opens that answer. When another question is clicked, it will close the previous answer and open the new one. I'd like to use slideUp/slideDown or fadeIn/fadeOut for that, but not essential.
The home page has a link that when clicked, I want taken to the faq page and also have 'open' a specific answer, both from the one click; slideDown or fadeIn again not essential.
Is there a JavaScript that can be used to perform the task?
I have seen some posts with setvisibility type code somewhat acceptable for the faq page, but not that I can activate from my home page.
I am a novice, so I ask for the html code too that I can insert on both pages. A bigger chore than usual I know!
Many thanks.
NOTE
I now see a problem with my idea because of the following. I didn't mention it before but it would be neccessary.
Let me try to explain it.
I now find that to have a link on one page open another page at a particular position down that page will
correctly position the page to that point IF previous content on that page is not hidden.
If previous content is visibility: hidden;, that point where the page will open at is innacurate. In other words, it opens at a point below intended, a point at which is correct if previous content is not hidden.
I hope that makes some sense.
I will soon look at whether display:none; is better suited for this before I look at my original questions.
Thanks to those who have helped me to date, you have spent a lot of time for me.
Try this one
Reference
$(function() {
$('div.answer').hide();
$('a.question').before('<span class="faqplusminus dark nounderline">[+]</span>');
$('a.question').click(function() {
$('div.answer').slideUp('slow', 'easeInOutExpo');
$('span.faqplusminus').html('[+]');
var slidedownelement = $(this).closest('div.faq').find('div.answer').eq(0);
if(!slidedownelement.is(':visible')) {
slidedownelement.slideDown('slow', 'easeInOutExpo');
slidedownelement.parent().find('span.faqplusminus').html('[-]');
}
});
});
You can add querystring parameters to the request for the faq page and read the querystring using javascript on the faq page. Depending on the parameters you pass, you could do your desired animations.
In home.html: You would create the links with the query string param like so:
Link to FAQ
In faq.html: you would need to read the querystring parameter and depending on the value, call the javascript function that actually handles the show/hide of questions.
To read querystring parameters in javascript you need to parse window.location.search. Here is a javascript helper that you can use:
var QueryString = function () {
// This function is anonymous, is executed immediately and
// the return value is assigned to QueryString!
var query_string = {};
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
// If first entry with this name
if (typeof query_string[pair[0]] === "undefined") {
query_string[pair[0]] = pair[1];
// If second entry with this name
} else if (typeof query_string[pair[0]] === "string") {
var arr = [ query_string[pair[0]], pair[1] ];
query_string[pair[0]] = arr;
// If third or later entry with this name
} else {
query_string[pair[0]].push(pair[1]);
}
}
return query_string;
} ();
You can then access QueryString.question
Context:
I work a student job transcribing paper reports in a webapp. It's old and we unfortunately can't change the source nor directly run a DB query.
It only checks if the unique ID exists once you submit the entire form, and you can't submit it unless it's entirely filled. Needless to say, it's a huge waste of time as you often transcribe the whole thing only to realise it's a duplicate.
Objective:
I made the userscript below that launches a search the search on the onblur of the unique ID's input(noReferenceDeclarant), checks if there are any matches (rows) and returns accordingly. Runs with Greasemonkey. The search form is in another page on the same domain. The search form does not take any URL arguments.
Can this be done without using an iframe (AJAX perhaps?)
This is a tool for my own productivity & to learn JS at the same time. As I'm still very much a beginner, any tips to make that code cleaner are welcome.
//Adding function to input's blur event
$(document).on ("blur", "#noReferenceDeclarant", isRefNumberExists);
//Vars
var noReferenceDeclarant = '';
var loadCode = 0;
var $searchForm;
//Fonctions
function isRefNumberExists ()
{
noReferenceDeclarant = $('#noReferenceDeclarant').val();
loadCode = 0;
//Make sure there's data in the input before proceeding
if (noReferenceDeclarant)
{
//Build search iframe
$searchForm = $('<iframe />', {
name: 'searchWindow',
src: 'rechercherGriIntranet.do?methode=presenterRechercher',
id: 'searchWindow',
width: 0,
height: 0
}).appendTo('body');
$searchForm.load(searchRefNumber);
}
}
function searchRefNumber()
{
var isExists = false;
//Check which "load" it is to avoid submit loops
if (loadCode === 0)
{
loadCode = 1;
//Filling search form with search term
$(this.contentDocument).find('#noReference').val(noReferenceDeclarant);
//Set search form preferences
$(this.contentDocument).find('#typeRapportAss').prop('checked', false);
$(this.contentDocument).find('#typeRapportAS').prop('checked', false);
$(this.contentDocument).find('#typeRapportSI').prop('checked', true);
//Submit the form
$(this.contentDocument).find('form:first').submit();
}
else if (loadCode === 1)
{
loadCode = 2;
//See if there are any tr in the result table. If there are no results, there a thead but no tr.
var foundReports = $(this.contentDocument).find('.resultatRecherche tr').length;
if (foundReports > 0)
{
if (confirm('A report matching this ID already exists. Do you want to display it?'))
{
//Modal window loading the report in an iframe. Not done yet but that's fairly straightforward.
}
else
{
//Close and return to the form.
}
}
}
//Reset variables/clean ressources
delete $searchForm;
$('#dateRedactionRapport').focus();
}
On the whole I've seen far, far worse code.
Ajax could do it, but then you'd just have to put the AJAX response into the DOM (as an iframe, most likely).
In this instance, I'd keep the approach you have. I think it is the sanest.j
Without the full context, there may be a way to clean up the loadCode -- but what you have is pretty same and works. A lot of folks would call it a semaphore, but that is just an issue of terminology.
The only thing I"d really clean up is recommend not calling the jQuery object so often..
// Many folks recommend that jQuery variables be named $<something>
var $doc = $(this.contentDocument);
doc.find('#typeRapportAss').prop('checked', false);
$doc.find('#typeRapportAS').prop('checked', false);
$doc.find('#typeRapportSI').prop('checked', true);
If you wanted to play with jQuery data structures, you could make a 'config' object that looks like this:
var formValues = {
typeRapportAs: false,
typeRapportAS: false,
typeRapportSI: true
};
then iterate over that to (using for ... in with .hasOwnProperty).
Not NEEDED for this project, what you are doing is fine, but it might make a learning exercise.
I have an XML file (consisting of a few data items, namely <Book> ) and a corresponding XSLT file that I created, which when opened up in a browser turns this list of books into an html table. The columns are named "Author", "Title", and "BookID" (they are ids of child nodes of <tr>).
Now I want to make the resulting page dynamic using jQuery, i.e. I want to make the resulting table rows to be sorted on the column I click on. However, while the table renders fine, the resulting jQuery code seems to have no effect.
I am not sure whether this is a result of bugs in my jQuery code, or whether I didn't include it properly, or both. I included two <script></script> tags in my XSL file (one to hotlink the jQuery library, the other to link to my code), but I'm not sure if this is the correct way to do it. also, can someone look over my jQuery code to find out if there's anything wrong (I'm a complete newbie to web programming, so please forgive my errors)?
Thanks!
$(document).ready(function() {
function sortBy(a, b, selectFunction) {
var a1 = selectFunction(a);
var b1 = selectFunction(b);
if (a1 < b1) {
return -1;
}
if (a1 > b1) {
return 1;
}
return 0;
}
function sortHelper(index) {
var rows = $('table tbody tr').get();
rows.sort(function(a, b) {
return sortBy(a, b, function(x) { return $(x).children('td').eq(index).text().toUpperCase(); });
});
rows.appendTo('tbody');
}
$('#Author').click(function() {
sortHelper(0);
});
$('#Title').click(function() {
sortHelper(1);
});
$('#BookID').click(function() {
sortHelper(2);
});
});
A stated in the comments .get() returns a javascript object. So to use rows.sort() you want the jQuery object.
// javascript
$(obj).get(0); // returns the first element from the query
// jquery
$(obj).eq(0); // return the first $(element) from the query.
Also one thing I noticed:
since you're accessing the td's by an id you can do something like:
var topRow = $("table tbody tr").eq(0),
topCells = topRow.find("td"); // expecting #author, #title, #bookid
topCells.click(function(){
sortHelper($(this).index()); // makes more sense this way
});
Other than that if you're loading external *.js files into your solution you'll be fine. If you're inserting code directly into the page use CDATA encoding as described here.
I am currently working on this script for Greasemonkey. The goal of this script is to remove posts from specific users on the feed of the website MeetMe.com.
My code is:
// ==UserScript==
// #name PostBeGone
// #namespace TestingNameSpace
// #include http://www.meetme.com/apps/home
// #version 1
// ==/UserScript==
var posterId;
var blacklist = new Array();
var toDelete;
blacklist [0] = 45112400; //These are just random peoples' user Id's that I am
blacklist [1] = 9649820; //using to test this script
blacklist [2] = 55907221;
blacklist [3] = 56788411;
window.onload = function checkAndRemove () {
var children = document.getElementById('feedReloadArea').childnodes;
alert(children); //alert says "undefined"
i = 0;
While (i < children.length)
{
posterId = children[i].getAttribute('data-poster');
toDelete = null;
i2 = 0;
while (i2 < blacklist.length)
{
if (posterId == blacklist[i2])
{
toDelete = children[i];
break;
}
i2++;
}
if (toDelete != null)
{
toDelete.parentNode.removeChild(toDelete);
}
i++;
}
}
Using various alerts with multiple executions, I know that the code executes up to the point where I have alert(children), which is returning undefined.
Prior to having window.onload = in my script, in scouring Google and this website for answers, I read many places that the problem might be that the script could be trying to execute before the page was loaded, so I added the window.onload =. The problem persisted, however, and I can't find any questions similar enough to mine to make sense of it.
To see the html code for the elements, I've been using Firefox's "Inspect Element" feature. A snippet of the html code on the page that may help is:
<div id="feedReloadArea" style="display: block;">
<div class="feedItemArea feedSpotlightHighlight" data-comment-maintenance="0" data-created-at="1360098729.05091" data-numeric-reference-id="" data-reference-uuid="0d76957f-2f64-4654-99ea-f67974116b32" data-entity="StatusUpdate" data-poster="59538173" data-uuid="b9e85465-5b91-4b5c-a443-c4e37d716481"></div><div class="feedItemArea" data-comment-maintenance="0" data-created-at="1360103761.624714" data-numeric-reference-id="" data-reference-uuid="c2c201ca-a391-4fff-aec2-9823a3e90815" data-entity="StatusUpdate" data-poster="45508368" data-uuid="11149a32-38cf-4919-b081-0bd39bdc49eb"></div>
<div class="feedItemArea" data-comment-maintenance="0" data-created-at="1360103737.756343" data-numeric-reference-id="" data-reference-uuid="997824a2-994c-467f-bfbe-aa4beb1e402f" data-entity="StatusUpdate" data-poster="38033716" data-uuid="bc075882-771c-4ee2-ad28-dbf21fbf3bd3"></div>
To clarify, that is only part of the HTML code. There are many of those classes on the feed, as each one represents one user's post. Also, each class has multiple within it, for things like the user's link and the user's profile picture. I, however, am wanting to remove full feedItemArea classes that have the same poster id as any that are on the blacklist.
I hope that I have been clear and concise enough to be easy to help, but if any other information is needed in order to help me, let me know and I will post it. My question is what is causing children to be undefined? Thanks in advance.
JavaScript is case-sensitive, and it's childNodes instead of childnodes. Btw, since you probably want to iterate element nodes only (no text nodes, comments, etc.), use the children collection. Also, you hardly need the window.onload, since GreaseMonkey scripts are executed on DOMready by default.
Capitalization!
var children = document.getElementById('feedReloadArea').childnNodes;
No idea what I'm doing or why it isn't working. Clearly not using the right method and probably won't use the right language to explain the problem..
Photogallery... Trying to have a single html page... it has links to images... buttons on the page 'aim to' modify the path to the images by finding the name currently in the path and replacing it with the name of the gallery corresponding to the button the user clicked on...
example:
GALLERY2go : function(e) {
if(GalleryID!="landscapes")
{
var find = ''+ findGalleryID()+'';
var repl = "landscapes";
var page = document.body.innerHTML;
while (page.indexOf(find) >= 0) {
var i = page.indexOf(find);
var j = find.length;
page = page.substr(0,i) + repl + page.substr(i+j);
document.body.innerHTML = page;
var GalleryID = "landscapes";
}
}
},
There's a function higher up the page to get var find to take the value of var GalleryID:
var GalleryID = "portfolio";
function findGalleryID() {
return GalleryID
}
Clearly the first varGalleryID is global (t'was there to set a default value should I have been able to find a way of referring to it onLoad) and the one inside the function is cleared at the end of the function (I've read that much). But I don't know what any of this means.
The code, given its frailties or otherwise ridiculousness, actually does change all of the image links (and absolutely everything else called "portfolio") in the html page - hence "portfolio" becomes "landscapes"... the path to the images changes and they all update... As a JavaScript beginner I was pretty chuffed to see it worked. But you can't click on another gallery button because it's stuck in a loop of some sort. In fact, after you click the button you can't click on anything else and all of the rest of the JavaScript functionality is buggered. Perhaps I've introduced some kind of loop it never exits. If you click on portfolio when you're in portfolio you crash the browser! Anyway I'm well aware that 'my cobbled together solution' is not how it would be done by someone with any experience in writing code. They'd probably use something else with a different name that takes another lifetime to learn. I don't think I can use getElement by and refer to the class/id name and parse the filename [using lots of words I don't at all understand] because of the implications on the other parts of the script. I've tried using a div wrapper and code to launch a child html doc and that come in without disposing of the existing content or talking to the stylesheet. I'm bloody lost and don't even know where to start looking next.
The point is... And here's a plea... If any of you do reply, I fear you will reply without the making the assumption that you're talking to someone who really hasn't got a clue what AJAX and JQuery and PHP are... I have searched forums; I don't understand them. Please bear that in mind.
I'll take a stab at updating your function a bit. I recognize that a critique of the code as it stands probably won't help you solve your problem.
var currentGallery = 'landscape';
function ChangeGallery(name) {
var imgs = document.getElementsByTagName("img") // get all the img tags on the page
for (var i = 0; i < imgs.length; i++) { // loop through them
if (imgs[i].src.indexOf(currentGallery) >= 0) { // if this img tag's src contains the current gallery
imgs[i].src = imgs[i].src.replace(currentGallery, name);
}
}
currentGallery = name;
}
As to why I've done what I've done - you're correct in that the scope of the variables - whether the whole page, or only the given function, knows about it, is mixed in your given code. However, another potential problem is that if you replace everything in the html that says 'landscape' with 'portfolio', it could potentially change non-images. This code only finds images, and then replaces the src only if it contains the given keyword.